Promise介绍--异步原理
2017-11-21 00:03
162 查看
这部分内容源于知乎上的一个提问。
之前我们说过
知乎的问题也有何幻大神详细的讲解。这里我就简单的说一下吧。
我们都知道
所以,浏览器会维护一个任务队列(
我之前也一直都以为浏览器中只有一个任务队列,看到这个问题后才知道。原来浏览器中的任务队列不止一个,且优先级也不同。基本上可以分为如下两种:
setImmediate, I/O, UI rendering
MutationObserver
我们看到原生
在执行完主线程上的所有任务时,会先去查看
我们看一个例子,并详细解释它的执行流程。
结果如代码中注释所示。具体执行步骤如下:
①代码从上到下执行,先打印出
②执行到第一个
③执行
④打印
⑤执行第二个
⑥主线程执行完毕则检查
⑦然后检查
⑧再次检查
⑨最后检查
规范中的流程是这个样子,但是不同的浏览器中,实际输出的结果可能会不相同。以上是最新版本的chrome中测试结果。
最后,推荐一篇外国友人的博客,我就是看了这篇文章才完全弄清楚的,里面内容讲的特别详细。
setTimeout(function(){console.log(4)},0); new Promise(function(resolve){ console.log(1) for( var i=0 ; i<10000 ; i++ ){ i==9999 && resolve() } console.log(2) }).then(function(){ console.log(5) }); console.log(3); // 1 // 2 // 3 // 5 // 4
之前我们说过
then方法添加的回调函数都是异步执行的,所以按照我们正常的认知,结果应该是
12345,因为
4是先添加到异步队列,而
5在之后添加到异步队列。
知乎的问题也有何幻大神详细的讲解。这里我就简单的说一下吧。
我们都知道
javascript是单线程的,也就是说,一个时间只能做一件事。所以,所有的任务都要按照一定的顺序排队,然后一个一个执行。如果所有的任务都是同步的,那就没有什么问题,代码按照从前到后的顺序依次执行就可以了,但我们实际工作过程中,难免会有一些操作需要异步执行——比如事件,比如ajax,比如
setTimeout。
所以,浏览器会维护一个任务队列(
task queue),任务队列是先进先出的,也就是说,先进入任务队列的会先执行。当主线程任务执行完毕,就会查看任务队列中有没有新任务,如果有,则把第一个任务放到主线程中执行,以此循环往复,这个过程也就是
Event loops。
我之前也一直都以为浏览器中只有一个任务队列,看到这个问题后才知道。原来浏览器中的任务队列不止一个,且优先级也不同。基本上可以分为如下两种:
macro-task: script(整体代码), setTimeout, setInterval,
setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe,
MutationObserver
我们看到原生
Promise和
setTimeout分别属于
micro-task和
macro-task。我们之前说的异步任务队列,指的是
macro-task。而
micro-task的执行顺序,与之不同。
在执行完主线程上的所有任务时,会先去查看
micro-task队列中有没有任务,如果有,则依次执行
micro-task队列中的所有任务,之后才去查看
macro-task队列。每次拿到
macro-task队列上任务并执行之后,都会去检查
micro-task队列,以此循环。所以上面题目中结果是
12354就很明了了。
我们看一个例子,并详细解释它的执行流程。
console.log('script1'); setTimeout(function() { console.log('setTimeout1'); }, 300); Promise.resolve().then(function() { console.log('promise1'); }).then(function() { console.log('promise2'); }); console.log('script2'); setTimeout(function() { console.log('setTimeout2'); Promise.resolve().then(function() { console.log('promise3'); }) }, 0); // script1 // script2 // promise1 // promise2 // setTimeout2 // promise3 // setTimeout1
结果如代码中注释所示。具体执行步骤如下:
①代码从上到下执行,先打印出
script1。
②执行到第一个
setTimeout时,发现300ms后把函数添加到
macro-task队列中。
③执行
Promise时,依次把输出
promise1和
promise2的任务添加到
micro-task队列。
④打印
script2。
⑤执行第二个
setTimeout时因为设置的是0ms,所以立即(其实浏览器有最少4ms的限制)添加到
macro-task队列中。
⑥主线程执行完毕则检查
micro-task队列并执行,输出
promise1和
promise2。
⑦然后检查
macro-task队列,输出
setTimeout2,并把输出
promise3的任务添加到
micro-task队列。
⑧再次检查
micro-task队列并执行,输出
promise3。
⑨最后检查
macro-task队列,输出
setTimeout1,因为它是300ms后添加到
macro-task队列,所以后输出。
规范中的流程是这个样子,但是不同的浏览器中,实际输出的结果可能会不相同。以上是最新版本的chrome中测试结果。
最后,推荐一篇外国友人的博客,我就是看了这篇文章才完全弄清楚的,里面内容讲的特别详细。
相关文章推荐
- promise异步编程的原理
- 异步javascript的原理和实现技巧介绍
- js异步发展历史与Promise原理分析
- Promise原理讲解 async+await应用(异步回调解决方案)
- C++异步调用利器future/promise实现原理
- 异步javascript的原理和实现技巧介绍
- 简单介绍Python的Tornado框架中的协程异步实现原理
- 消息队列技术的介绍和原理(MQ)
- Ajax(一) — Ajax的核心与异步原理
- android AsyncTask介绍 异步更新UI
- ARP欺骗原理详细介绍
- cas原理介绍
- PHP会话控制之Session介绍原理
- XMPP协议的原理介绍
- XMPP协议的原理介绍
- json原理分析及实例介绍
- dubbo学习过程、使用经验分享及实现原理简单介绍
- Https原理介绍
- css中clearfix清除浮动的用法及其原理示例介绍
- WebSocket介绍与原理