资讯专栏INFORMATION COLUMN

Promise介绍--异步篇

hersion / 3047人阅读

摘要:知乎的问题也有何幻大神详细的讲解。我们之前说的异步任务队列,指的是。每次拿到队列上任务并执行之后,都会去检查队列,以此循环。主线程执行完毕则检查队列并执行,输出和。以上是最新版本的中测试结果。

这部分内容源于知乎上的一个提问。

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

我们看到原生PromisesetTimeout分别属于micro-taskmacro-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时,依次把输出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中测试结果。

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/86680.html

相关文章

  • promise介绍--实现

    摘要:内部总体上分为两种情况,一种是当前对象状态已经变为或,此时则直接把响应的回调函数添加到异步队列中,另一种情况是当前对象状态还是,此时则把响应的回调函数依次添加到数组中。 今天,我带着大家一步一步跟着规范实现一个自己的Promise,大家可以对照我的第二篇文章Promise介绍--规范篇或官方规范来一一学习。 Promise内部有三个固定的状态,我们在文件中提前定义。 const PEN...

    shery 评论0 收藏0
  • ES6-7

    摘要:的翻译文档由的维护很多人说,阮老师已经有一本关于的书了入门,觉得看看这本书就足够了。前端的异步解决方案之和异步编程模式在前端开发过程中,显得越来越重要。为了让编程更美好,我们就需要引入来降低异步编程的复杂性。 JavaScript Promise 迷你书(中文版) 超详细介绍promise的gitbook,看完再不会promise...... 本书的目的是以目前还在制定中的ECMASc...

    mudiyouyou 评论0 收藏0
  • Promise介绍--规范

    摘要:规范中对于构造函数没有明确说明,所以在此处拿出来讲解一下。构造函数只接收一个参数,且该参数必须是一个函数,任何其他的值比如等都会报一个的错误。 本篇文章是Promise系列文章的第二篇,主要是讲解基于Promise/A+规范,在传入不同类型的参数时,promise内部分别会如何处理。本章的主要目的是让大家对promise有一个更加深入的理解,也为下一篇讲如何实现一个promise库做准...

    tylin 评论0 收藏0
  • promise介绍--基础

    摘要:请求的传统写法改为后的写法很显然,我们把异步中使用回调函数的场景改为了等函数链式调用的方式。数组中第一个元素是异步的,第二个是非异步,会立即改变状态,所以新对象会立即改变状态并把传递给成功时的回调函数。 前言 Promise,相信每一个前端工程师都或多或少地在项目中都是用过,毕竟它早已不是一个新名词。ES6中已经原生对它加以支持,在caniuse中搜索一下Promise,发现新版的ch...

    tanglijun 评论0 收藏0
  • 深入探析koa之异步回调处理

    摘要:而之后,我们得到的是一个是一个对象,我们可以使用语句定义回调函数,函数的内容呢,则是将读取到的返回给并继续让从断点处执行。 在上一篇中我们梳理了koa当中中间件的洋葱模型执行原理,并实现了一个可以让洋葱模型自动跑起来的流程管理函数。这一篇,我们再来研究一下koa当中异步回调同步化写法的原理,同样的,我们也会实现一个管理函数,是的我们能够通过同步化的写法来写异步回调函数。 1. 回调金字...

    Drinkey 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<