Promise介绍--异步篇

这部份内容源于知乎上的一个提问javascript

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在以后添加到异步队列。java

知乎的问题也有何幻大神详细的讲解。这里我就简单的说一下吧。ajax

咱们都知道javascript是单线程的,也就是说,一个时间只能作一件事。因此,全部的任务都要按照必定的顺序排队,而后一个一个执行。若是全部的任务都是同步的,那就没有什么问题,代码按照从前到后的顺序依次执行就能够了,但咱们实际工做过程当中,不免会有一些操做须要异步执行——好比事件,好比ajax,好比setTimeoutchrome

因此,浏览器会维护一个任务队列(task queue),任务队列是先进先出的,也就是说,先进入任务队列的会先执行。当主线程任务执行完毕,就会查看任务队列中有没有新任务,若是有,则把第一个任务放到主线程中执行,以此循环往复,这个过程也就是Event loopspromise

我以前也一直都觉得浏览器中只有一个任务队列,看到这个问题后才知道。原来浏览器中的任务队列不止一个,且优先级也不一样。基本上能够分为以下两种:浏览器

macro-task: script(总体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe, MutationObserver异步

咱们看到原生PromisesetTimeout分别属于micro-taskmacro-task。咱们以前说的异步任务队列,指的是macro-task。而micro-task的执行顺序,与之不一样。函数

在执行完主线程上的全部任务时,会先去查看micro-task队列中有没有任务,若是有,则依次执行micro-task队列中的全部任务,以后才去查看macro-task队列。每次拿到macro-task队列上任务并执行以后,都会去检查micro-task队列,以此循环。因此上面题目中结果是12354就很明了了。oop

咱们看一个例子,并详细解释它的执行流程。测试

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时,依次把输出promise1promise2的任务添加到micro-task队列。

④打印script2

⑤执行第二个setTimeout时由于设置的是0ms,因此当即(其实浏览器有最少4ms的限制)添加到macro-task队列中。

⑥主线程执行完毕则检查micro-task队列并执行,输出promise1promise2

⑦而后检查macro-task队列,输出setTimeout2,并把输出promise3的任务添加到micro-task队列。

⑧再次检查micro-task队列并执行,输出promise3

⑨最后检查macro-task队列,输出setTimeout1,由于它是300ms后添加到macro-task队列,因此后输出。

规范中的流程是这个样子,可是不一样的浏览器中,实际输出的结果可能会不相同。以上是最新版本的chrome中测试结果。

最后,推荐一篇外国友人的博客,我就是看了这篇文章才彻底弄清楚的,里面内容讲的特别详细。

相关文章
相关标签/搜索