JavaScript的异步机制 Asynchronous

2019-10-08  本文已影响0人  四月白绵羊

JavaScript是一个单线程的编程语言,即便它包含了 awaitasync 的关键字也改变不了这个事实。
那么,作为单线程语言的JS是怎么实现异步操作的呢?

Synchronous


首先,先了解一下JS的同步执行方式。例如下面的🌰:

const second = () => {
    console.log('Hello there!');
}

const first = () => {
    console.log('The Start.');
    second();
    console.log('The End.');
}

可以想象输出会是:

Start.
Hello World!
End.

这是一个同步调用的例子,那我们来说说JS执行机制背后包含的东西:Execution Context 和 Call Stack

Execution Context 执行上下文

每一段代码都运行在自己的上下文之中。例如,回调函数的上下文就是它被定义的地方,包括可获取的变量。

Call Stack 调用栈

Stack就是一个LIFO先进后出的结构。后进入的函数先被执行和释放。还是上面那个例子,每个函数进入栈的顺序如下图:


image.png

所以,发生了什么?

首先,主函数先被运行了,于是主函数包括其上下文Context都被放进了Stack。接着first()及其上下文也被放进了Stack。由于first包含了三个子函数,于是console.log('The Start.');也被放进Stack,且马上被执行,执行完后被释放。同样second()也被放入、执行和释放。然后console.log(‘The End’)也被放入、执行和释放。由于first()的所有内容已经执行完毕,也被释放。最后主函数被释放。

这就是一个完整的同步执行的过程。那么异步执行呢?

Asynchronous


前面也说到了,JS是一个单线程的语言,所以JS并没有办法靠自己完成异步的操作,它需要依赖于浏览器环境或者Node.js环境。先来看一张图:


image.png

这里出现了三个新的东西:Event Loop,Web Api 和Message Queue。

注意这三部分都不是属于JavaScript Engine 的范畴。而是属于浏览器JS运行环境的。

在下面这个🌰中:

const networkRequest = () => {
  setTimeout(() => {
    console.log('Async Code');
  }, 2000);
};
console.log('Hello World');
networkRequest();
console.log('The End');

它的执行过程是:


1_sOz5cj-_Jjv23njWg_-uGA.gif

注意到,这里一个显著的区别就是,当setTimeout被调用的时候,它实际上在Web Api中设置了一个定时器,然后接着执行同步操作。这个计时器可能在同步操作结束之前或者之后结束,但无论如何回调函数都会先被放进Message Queue。

等到Call Stack 中的任务都执行完了之后,Event Loop会来查询Message Queue之中是否有等待被执行的任务。如果有,就取出第一个任务放进Call Stack执行。以此类推,直到Message Queue空了。

Message Queue中同样包含事件响应,如鼠标点击监听等。

Conclusion

所以JS的执行本质是一个调用栈。而它的异步操作实际上是依赖于浏览器当中的JS运行环境来帮助JS把异步调用的返回函数存放在消息队列当中,依赖于Event Loop进行轮训,当Call Stack一空,就把任务从Message Queue中取出。

这样的执行方式也决定了,在一个函数当中,一个异步操作即使是一开头就被执行了,它的回调函数还是必须等到所有同步操作完成了之后才会被调用。

这里也涉及到了另一个问题,就是如果有多个异步操作,那么它们的回调函数执行顺序是怎么样的呢?
简洁的答案是:如果所有的异步回调函数都在同一个队列之中,如Message Queue,那么FIFO先进先出。但是实际上有许多不同的队列,对应了不同的执行优先级,例如 micro-task queue macro-task queuemicro-task queue 当中的任务就会被优先执行。Promise就是基于micro-task queue实现的,而setTimeout是基于macro-task queue实现的。所以Promise的回调函数会比setTimeout的回调函数先执行。具体不同优先级的Queue日后有机会再说说。

Reference

上一篇 下一篇

猜你喜欢

热点阅读