From e83cf4c5170de565a273bce544732df70e8a9513 Mon Sep 17 00:00:00 2001 From: Lellansin Date: Tue, 7 Feb 2017 15:08:39 +0800 Subject: [PATCH] Update event-async.md --- README.md | 28 ++++++++++++------------ sections/event-async.md | 47 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 0573a0b..e5817ca 100644 --- a/README.md +++ b/README.md @@ -26,10 +26,10 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过 ### 常见问题 -* js 中什么类型是引用传递, 什么类型是值传递? 如何将值类型的变量以引用的方式传递? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md#q-value) +* js 中什么类型是引用传递, 什么类型是值传递? 如何将值类型的变量以引用的方式传递? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md#q-value) * js 中, 0.1 + 0.2 === 0.3 是否为 true ? 在不知道浮点数位数时应该怎样判断两个浮点数之和与第三数是否相等? -* const 定义的 Array 中间元素能否被修改? 如果可以, 那 const 的意义是? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md#q-const) -* Javascript 中不同类型以及不同环境下变量的内存都是何时释放? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md#q-mem) +* const 定义的 Array 中间元素能否被修改? 如果可以, 那 const 的意义是? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md#q-const) +* Javascript 中不同类型以及不同环境下变量的内存都是何时释放? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md#q-mem) [阅读更多](https://github.com/ElemeFE/node-interview/blob/master/sections/js-basic.md) @@ -46,9 +46,9 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过 ### 常见问题 -* a.js 和 b.js 两个文件互相 require 是否会死循环? 双方是否能导出变量? 如何从设计上避免这种问题? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md#q-loop) -* 如果 a.js require 了 b.js, 那么在 b 中定义全局变量 `t = 111` 能否在 a 中直接打印出来? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md#q-global) -* 如何在不重启 node 进程的情况下热更新一个 js/json 文件? 这个问题本身是否有问题? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md#q-hot) +* a.js 和 b.js 两个文件互相 require 是否会死循环? 双方是否能导出变量? 如何从设计上避免这种问题? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md#q-loop) +* 如果 a.js require 了 b.js, 那么在 b 中定义全局变量 `t = 111` 能否在 a 中直接打印出来? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md#q-global) +* 如何在不重启 node 进程的情况下热更新一个 js/json 文件? 这个问题本身是否有问题? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md#q-hot) [阅读更多](https://github.com/ElemeFE/node-interview/blob/master/sections/node-basic.md) @@ -56,18 +56,18 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过 * [`[Basic]` Promise](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#Promise) * [`[Doc]` Events (事件)](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#Events) -* `[Doc]` Timers (定时器) +* [`[Doc]` Timers (定时器)](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#Timers) * [`[Point]` 阻塞/异步](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#阻塞/异步) -* `[Point]` 并行/并发 +* [`[Point]` 并行/并发](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#并行/并发) ### 常见问题 -* Promise 中 .then 的第二参数与 .catch 有什么区别? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-1) -* Eventemitter 的 emit 是同步还是异步? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-2) -* 如何判断接口是否异步? 是否只要有回调函数就是异步? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-3) -* nextTick, setTimeout 以及 setImmediate 三者有什么区别? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-4) -* 如何实现一个 sleep 函数? [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-5) -* 如何实现一个异步的 reduce? (注:不是异步完了之后同步 reduce) [答案/讨论](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-6) +* Promise 中 .then 的第二参数与 .catch 有什么区别? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-1) +* Eventemitter 的 emit 是同步还是异步? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-2) +* 如何判断接口是否异步? 是否只要有回调函数就是异步? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-3) +* nextTick, setTimeout 以及 setImmediate 三者有什么区别? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-4) +* 如何实现一个 sleep 函数? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-5) +* 如何实现一个异步的 reduce? (注:不是异步完了之后同步 reduce) [more](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md#q-6) [阅读更多](https://github.com/ElemeFE/node-interview/blob/master/sections/event-async.md) diff --git a/sections/event-async.md b/sections/event-async.md index 72a14bf..3f4514a 100644 --- a/sections/event-async.md +++ b/sections/event-async.md @@ -117,8 +117,51 @@ Node.js 中执行 js 代码的过程是单线程的. 只有当前代码都执行 如果在线上的网站中出现了死循环的逻辑被触发, 整个进程就会一直卡在死循环中, 如果没有多进程部署的话, 之后的网站请求全部会超时, js 代码没有结束那么事件队列就会停下等待不会执行异步, 整个网站无法响应. -整理中 +## Timers + +在笔者这里将 Node.js 中的异步简单的划分为两种, 硬异步和软异步. + +硬异步是指由于 IO 操作或者外部调用走 libuv 而需要异步的情况. 当然, 也存在 readFileSync, execSync 等例外情况, 不过 node 由于是单线程的, 所以如果常规业务在普通时段执行可能比较耗时同步的 IO 操作会使得其执行过程中其他的所有操作都不能响应, 有点作死的感觉. 不过在启动/初始化以及一些工具脚本的应用场景下是完全没问题的. 而一般的场景下 IO 操作都是需要异步的. + +软异步是指, 通过 setTimeout 等方式来实现的异步. 关于 nextTick, setTimeout 以及 setImmediate 三者的区别参见[该帖](https://cnodejs.org/topic/5556efce7cabb7b45ee6bcac) + +**Event loop 示例** + +``` + ┌───────────────────────┐ +┌─>│ timers │ +│ └──────────┬────────────┘ +│ ┌──────────┴────────────┐ +│ │ I/O callbacks │ +│ └──────────┬────────────┘ +│ ┌──────────┴────────────┐ +│ │ idle, prepare │ +│ └──────────┬────────────┘ ┌───────────────┐ +│ ┌──────────┴────────────┐ │ incoming: │ +│ │ poll │<─────┤ connections, │ +│ └──────────┬────────────┘ │ data, etc. │ +│ ┌──────────┴────────────┐ └───────────────┘ +│ │ check │ +│ └──────────┬────────────┘ +│ ┌──────────┴────────────┐ +└──┤ close callbacks │ + └───────────────────────┘ +``` + +关于事件循环, Timers 以及 nextTick 的关系详见官方文档 [The Node.js Event Loop, Timers, and process.nextTick()](https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/) ## 并行/并发 -整理中 +并行 (Parallel) 与并发 (Concurrent) 是两个很常见的概念. + +可以看 Erlang 作者 Joe Armstrong 的博客 ([Concurrent and Parallel](http://joearms.github.io/2013/04/05/concurrent-and-parallel-programming.html)) + +![con_and_par](http://joearms.github.io/images/con_and_par.jpg) + +并发 (Concurrent) = 2 队列对应 1 咖啡机. + +并行 (Parallel) = 2 队列对应 2 咖啡机. + +Node.js 通过事件循环来挨个抽取实践队列中的一个个 Task 执行, 从而避免了传统的多线程情况下 `2个队列对应 1个咖啡机` 的时候上线文切换以及资源争抢/同步的问题, 所以获得了高并发的成就. + +至于在 node 中并行, 你可以通过 cluster 来再添加一个咖啡机.