简述以下代码的输出结果,并解释执行过程:
import { once, EventEmitter } from 'node:events';
import process from 'node:process';
const ee = new EventEmitter();
process.nextTick(() => {
ee.emit('myevent', 42);
});
const [value] = await once(ee, 'myevent');
console.log(value);
const err = new Error('kaboom');
process.nextTick(() => {
ee.emit('error', err);
});
try {
await once(ee, 'myevent');
} catch (err) {
console.error('error happened', err);
}
以上代码来自这里
里面涉及到的基础知识点有:
Promiseasync/awaitnexttick 队列EventEmitter最后,这真的不算八股,AI 当然可以解释清楚,但这么一段简单清晰的代码,你还不知所以然的话,那对着 Vibe Coding 出来的屎山,最后只能束手无策了。
1
Zhuzhuchenyan 22 小时 58 分钟前 哈哈,这不是几年前我校招的时候面试官最“喜欢”的面试题嘛
看我随手出一道,console.log 1234 才是味道最足的 console.log(1); setTimeout(() => console.log(2), 0); process.nextTick(() => { console.log(3); queueMicrotask(() => console.log(4)); }); queueMicrotask(() => { console.log(5); process.nextTick(() => console.log(6)); }); new Promise(resolve => { console.log(7); resolve(); console.log(8); }).then(() => { console.log(9); process.nextTick(() => console.log(10)); queueMicrotask(() => console.log(11)); }); new Promise(resolve => { console.log(12); setTimeout(() => { console.log(13); resolve(); }, 0); }).then(() => { console.log(14); }); (async () => { console.log(15); await void 0; console.log(16); process.nextTick(() => console.log(17)); queueMicrotask(() => console.log(18)); })(); console.log(19); |
2
craftsmanship 22 小时 57 分钟前 via Android
@Zhuzhuchenyan 🆘啊
|
3
lqm 22 小时 53 分钟前
AI 既然清清楚楚,那怎么会堆出类似错误的屎山
|
4
tearnarry 22 小时 48 分钟前
既然 AI 可以解释清楚
1. 不会 Vibe Coding 出来屎山 2. 如果有 Vibe Coding 出来的屎山,继续让 AI 修复即可 |
5
4seasons 22 小时 44 分钟前
@Zhuzhuchenyan 这个玩意儿我寻思着真的有人能分析出来吗?
|
6
lanced 21 小时 25 分钟前
@Zhuzhuchenyan 太经典了
|
7
wuxilaoshiren 21 小时 22 分钟前
典典典 前些年面试就喜欢问这个
但是随着 AI 的到来,感觉看这些都没意义了 |
8
ssssiiiirren 21 小时 22 分钟前
哥们你这题目出的有问题,你这程序但凡要能运行的下去,就必须先打印 42 ,然后后面就能推出来了。
如果不先打印 42 ,await 那里就卡住了。 |
9
chenluo0429 20 小时 57 分钟前 via Android
我面试的时候从来不会问这些。一个合格的开发应当知道一些会引发典型的回调/异步等时序难以确定的场景,然后在正常的开发过程中,别这么用他们
|
10
Ketteiron 20 小时 40 分钟前
我说个暴论,凡是用得上 EventEmitter 的项目,99%是屎山
|
11
SanjinGG 20 小时 6 分钟前
能出现这种代码的公司还有必要去?
|
12
woodytang 18 小时 0 分钟前
import { once, EventEmitter } from 'node:events';
import process from 'node:process'; //定义一个 事件喇叭 const ee = new EventEmitter(); process.nextTick(() => { //在异步队列里 喇叭发消息 ee.emit('myevent', 42); }); // 只处理一次的监听器,在主流程执行完后,会听到这个消息 const [value] = await once(ee, 'myevent'); console.log(value); const err = new Error('kaboom'); process.nextTick(() => { // 在异步队列里 喇叭发消息,但这次发的是一个 nodejs bug 设计,'error'是 nodejs hardcode 的 key ,你发这个消息相当于抛异常 ee.emit('error', err); }); try { //虽然你没有监听'error', 但是 nodejs 内部强迫你监听了 await once(ee, 'myevent'); } catch (err) { //虽然只是发了个消息,但是确抛了个异常 console.error('error happened', err); } 这个是大傻逼设计,消息是消息,异常是异常,违反 solid 原则,后来的 bunjs 运行时 不鼓励使用这种方式控制流程, 一般会使用 promise ,在异步方法里 throw 异常,然后使用 Controller ,控制异步任务的退出,也可以。 另外 现代化运行时框架 认为,用事件做控制流是反模式 是 anti pattern ,会把代码搞得很乱,不可追溯,一般采用 回调 来响应事件,更符合函数式编程 这样可以过面试吗? |
13
superhot OP @Zhuzhuchenyan 太可怕了……
@lqm @tearnarry 只要 AI 不能做到 100% 准确,就需要最终由人来把关,前提是你真的有能力做到这点。 @wuxilaoshiren 确实没必要纠结八股,但基础还是要有的。 @ssssiiiirren 顺序也许好推,但解释原理呢? @chenluo0429 也许有更好的方式考察这些基础,想问一下都有哪些“会引发典型的回调/异步等时序难以确定的场景” @Ketteiron 为什么呢?我的理解是 Node 中的很多类都基于 EventEmitter ,比如 Stream ,所以是很有必要去了解的。 @woodytang 受教了,“用事件做控制流是反模式 是 anti pattern ,会把代码搞得很乱,不可追溯,一般采用 回调 来响应事件,更符合函数式编程”,可以再深入解释一下这段话吗?回调响应事件,不就是 emitter.on 吗? |
14
woodytang 16 小时 25 分钟前
@superhot
事件是这样的,emit("xxx",'咕咕咕'), listen('xxx',(text)=>{console.log("通知":text)}) 回调是这样的 async fn(handle){ handle('咕咕咕') } handle(text){ console.log("通知":text) } await fn(handle) -------- 它们本质都是 解决异步情况下,也就是在不确定什么时候的情况下,A 给 B 发消息的问题,, 事件是发出去不管的,它和监听者没有绑定关系 回调是是绑定的,可以追踪,可以测试的 但是事件可以批量订阅,你要发广播可以使用事件, 如果你只是要链式执行,使用回调 |
15
songray 7 小时 27 分钟前
EventEmitter 和 process 都是 node 独有的,所以这个问题与其说是考察 JS 相关,不如说是考察 Node.js 实现...
更不用说 Node 项目八百年都用不上这些玩意。 浏览器环境下的事件循环就那几个 API ,根本没这么麻烦。 -------------- 再提一点,当初 Ryan 搞出 node:events 纯粹是因为当时的 JS 还没有 Promise ,observable ,stream 。只有回调、setTimeout 和 polling 。 EventEmitter 就是蛮荒时代不成熟的造物而已,现在面试还问这个,跟问 IE 浏览器兼容没什么区别,怕不是喝大了。 |
17
GiantHard 6 小时 6 分钟前 > 最后,这真的不算八股,AI 当然可以解释清楚,但这么一段简单清晰的代码,你还不知所以然的话,那对着 Vibe Coding 出来的屎山,最后只能束手无策了。
确实不算八股,这算 NodeJS 实现细节;但既然 AI 可以解释清楚,为啥还会不知所以然? 我的一个感受是,现在 LLM 的知识广度已经远远超过人类了,考察一个人是否了解一项技术细节意义确实没以前那么重要。 > 只要 AI 不能做到 100% 准确,就需要最终由人来把关,前提是你真的有能力做到这点。 人也做不到 100% 准确,要不然就不会有 QA 团队了。之所以我们需要人类开发者,是因为人类开发者拥有一些 LLM 不具备的优势。 我觉得的人相对于 AI 的一个优势就是读不懂一些晦涩的代码,现在 LLM 读混淆后的 JS 都能把业务逻辑还原得八九不离十,这对于绝大多数人类来说是非常艰巨的任务。但也正是因为这点,人厌恶读起来不舒服的代码,在代码出现坏味道的时候,人的潜意识中就会产生抗拒情绪,这种情绪又会反过来让人避免编写有坏味道的代码: > 一个合格的开发应当知道一些会引发典型的回调/异步等时序难以确定的场景,然后在正常的开发过程中,别这么用他们 因此,只要 AI 生成的代码还需要人类参与维护,就需要有品味好的开发者充当 AI 代码的质检员,要么拒绝晦涩的代码进入代码库,要么在代码库出现坏味道的时候,能够自己动手或者指挥 AI 去重构、重写。 |
18
wangtian2020 5 小时 58 分钟前
setTimeout(() => {
console.log('a') setTimeout(() => console.log('b'), 1) }, 1) setTimeout(() => { console.log('c') }, 15) |
19
superhot OP @GiantHard 我个人理解是,只要 AI 无法消除幻觉,做到 100% 准确,就始终需要使用者具备判断 AI 是否准确的能力,而非照单全收。在这个例子里面,能断定 AI 可以解释清楚的前提是,你能完全理解以上提及的知识点。否则 AI 自圆其说,也许会把你说服,但却是在扯谎,那就非常糟糕了。
> 我的一个感受是,现在 LLM 的知识广度已经远远超过人类了,考察一个人是否了解一项技术细节意义确实没以前那么重要。 说实话,确实如此,但还是会有所顾虑,无法做到完全信任。另一方面,在 AI 的知识深度与广度都远超人类的今天,我们这些技术人员应该把精力放在哪里呢?有些迷茫。 |
20
KisekiRemi 4 小时 47 分钟前
典中典,麻烦 OP 报一下你公司名,以后避开你司合作
|
21
caiyuan 4 小时 34 分钟前
非常不喜欢使用发布订阅这种方式,维护非常难受。永远不清楚哪里发布了,哪里订阅了。
|
22
GiantHard 2 小时 2 分钟前
> 我个人理解是,只要 AI 无法消除幻觉,做到 100% 准确,就始终需要使用者具备判断 AI 是否准确的能力,而非照单全收。在这个例子里面,能断定 AI 可以解释清楚的前提是,你能完全理解以上提及的知识点。否则 AI 自圆其说,也许会把你说服,但却是在扯谎,那就非常糟糕了。
我感觉你这里已经提到了一个比知识面广更重要的特质了,就是不轻易被 AI 说服,或者说,要具有批判性思维。 > 另一方面,在 AI 的知识深度与广度都远超人类的今天,我们这些技术人员应该把精力放在哪里呢?有些迷茫。 如果是为了工资而编程,那么不管有没有 AI ,技术人员是不是都应该把精力放在搞钱上?卖时间的就应该想办法让单位时间更值钱,卖体力的就应该想办法让劳动产出更值钱。 |