原贴地址 https://cnodejs.org/topic/5c4ebbb23819b801aa5a20cd

评论

首先,你得知道阻塞(blocking)和非阻塞(non-blocking)有啥区别。

你可以把Node.js看做一个人+一个团队:

JS的执行部分看做是一个人,叫他小杰;
调用libuv实现的IO操作的部分看做是一个团队,比如李家团;
小杰只有他自己1个人(单线程),他同一时间内只能干一件事,这部分是阻塞的,一项工作(语句)执行完才能执行下一项,比如一个for循环:

for(let t=0;t<10000;t++){
	console.log(t);
}

因为只有第一次循环执行完才能执行第二次循环,第二次循环执行完才能执行第三次……所以小杰重复做了一万次工作(累死),假设每个工作要做1秒,那么小杰做完所有工作要花1万秒。
这就叫做阻塞。

并不是所有工作都必须让小杰自己去做,比如送信(IO)这种事情就可以委托给李家团来做,李家团是一个团队,有无数个人随时等着接活。
某一天小杰想写两封信分别送给不同的人,于是他先写第一封信,花了1个小时时间,然后直接把这封信交给李家团,李家团派手下的人去送信,并承诺小杰,当送信的人回来的时候(事件),会告诉(回调)小杰信是否送到了。这时候小杰可以等着李家团的消息,但是会闲的蛋疼,于是他决定不等,了直接写第二封信。过了半小时,李家团送信的人回来了(事件触发),来到小杰门前敲小杰的们,此时小杰正在专注地写一段文字,听到敲门声,他说:“稍等一下(阻塞),这句马上写完。”等他写完了这一句(响应事件),就放下笔,去开门,李家团的人告诉他(回调)信送到了,小杰说了声谢谢就让对方回去了。然后小杰又继续拿起了笔写信,又过了半小时总算写完,又让李家团去送信……
李家团送信的时候不会阻止(阻塞)小杰做其他工作,这就是非阻塞。

小杰第一封信写了1小时,第二封信也写了1小时,李家团送第一封信用了半小时,送第二封信我们先不看;
也就是说从小杰开始写第一封信到写完第二封信,一共花了2小时时间,如果第一封信是小杰亲自去送,假设他来回也只花半小时,那么那么他第二封信写完就会比原来晚半小时。
刚才说李家团手下人很多,就算小杰提前写好了10封信,一封一封交给李家团,李家团也可以派10个人同时送这些信,假设最远的路途来回需要40分钟,那么小杰也可以在40分钟后知晓全部10封信的运送结果。
那如果是100封信、1000封信呢?知道所有信的运送结果的时间几乎等于送得最远的一封信的来回时间。

这就是为什么Node单线程还能适用于IO密集型应用,一方面李家团足够强大能同时做多个跑腿工作,另一方面李家团和小杰之间约定了一个高效的合作流程(事件驱动的非阻塞回调)。

Node当中,fs.writeFile是把writeFile这件事委托给李家团去做了,李家团执行这个工作的时候,小杰可以做其他事情;而fs.writeFileSync虽然也是交给李家团去做,但小杰执意要等李家团回信儿了才肯做其他事情,等待的这段时间小杰是被阻塞的,没法做其他事情(不是你自己愿意等的吗喂?!)。