YIXUNFE / blog

文章区
151 stars 25 forks source link

Event Loop & Message Queue #34

Open YIXUNFE opened 8 years ago

YIXUNFE commented 8 years ago

Event Loop & Message Queue

这些年提到 Event Loop 的文章已经有很多了,为什么在这里又重新拾起这个话题,主要还是希望大家能对 Javascript 的运行环境是如何处理异步操作有更多的了解。当回忆起最初写 Javascript 程序的时候,想必你也和我一样,困惑于 Javascript 语音的异步特性。比如:

setTimeout(function () {
  console.log(0)
}, 0)
console.log(1)

//
//1
//0

这个简单的程序的运行结果,在当时也出乎了我的预料。


非阻塞 I/O

由于 Javascript 是单线程运行的,在遇到 I/O 操作时无法开启多线程协作,所以几乎所有的 I/O 都具有异步非阻塞特性,包括 HTTP 请求、数据库访问、磁盘读写等。它们都通过提供一个事件或回调函数以便我们可以在任务结束后执行相应的方法。


Message Queue

消息队列是一个存储消息的地方,不同的消息可能存储在不同的队列中。消息队列中的每一个消息都与一个函数相关联。

当程序遇到诸如 setTimeout 等异步处理方法时,方法的回调事件会在等待时间结束后产生一个消息放入消息队列中。而当两个 setTimeout 方法拥有相同的时间参数时,它们产生的消息将会被按执行顺序放入消息队列。

setTimeout(function () {
  console.log(0)
}, 0)

setTimeout(function () {
  console.log(1)
}, 0)

//
//0
//1


Event Loop

事件循环是 Javascript 运行环境实现异步的一种方法。它通过将消息队列中的一个消息出队,并将与消息相关的回调函数推入一个栈中(一个消息并不一定具有回调函数)。待栈中的任务执行完毕后,主线程将会尝试继续在消息队列中寻找下一个(next tick)消息。

在事件循环的过程中执行消息时,必须在一个消息执行完毕后其他消息才能被执行。当一个消息执行时间过长时(比如浏览器提示程序执行时间过长时),可以考虑将消息拆分成多个。由于 click、'mousedown'、'setTimeout' 等可以随时产生消息,当此类消息被加入消息队列后,如果当前执行的消息还未结束,它们也需要等待当前消息执行完毕后才有可能被执行。

当遇到多个运行环境时,比如 iframe、Web Worker,它们都拥有自己的消息队列和事件循环。我们需要通过 postMessage 方法进行通信,这个方法会给监听了 message 事件的运行环境添加一个新消息。

0




参考资料:

http://blog.carbonfive.com/2013/10/27/the-javascript-event-loop-explained/

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop


Thanks