前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >settimeout(fn 0)与Promise的执行顺序

settimeout(fn 0)与Promise的执行顺序

作者头像
用户1065635
发布2019-03-21 11:03:34
1.3K0
发布2019-03-21 11:03:34
举报
文章被收录于专栏:前端社区前端社区

有这么一道题:

代码语言:javascript
复制
setTimeout(function() {
  console.log(1)
}, 0);

new Promise(function(resolve, reject) {
  console.log(2)
  for (var i = 0; i < 10000; i++) {
    if(i === 10) {console.log(10)}
    i == 9999 && resolve();
  }
  console.log(3)
}).then(function() {
  console.log(4)
})

console.log(5);

结果是怎样的呢?

真正结果是: 2 10 3 5 4 1,不知你写对了没有。如果你的答案错了,没关系,接着往下读,会为你一一解惑。

这里涉及到三个“何时”:

  • setTimeout(fn, 0)何时执行
  • promise函数何时执行
  • then何时执行

下面我们来一一分析。

1. setTimeout(fn, 0)何时执行?

我们知道,JavaScript是基于事件驱动单线程执行的,所有任务都需要排队,也就是说前一个任务结束,才会去执行下一个任务。而像settimeout、ajax等异步操作的回调,会进入”任务队列“中,而且只有主线程中没有执行任何同步代码的前提下,才会执行异步回调。

而settimeout(fn, 0)表示立即执行,也就是用来改变任务的执行顺序,要求浏览器”尽可能快“的进行回调。

2. promise何时执行?

我们依旧以上面代码为例:

代码语言:javascript
复制
new Promise(function(resolve, reject) {
  console.log(2)
  for (var i = 0; i < 10000; i++) {
    if(i === 10) {console.log(10)}
    i == 9999 && resolve();
  }
  console.log(3)
})

结果: 2 10 3 从结果可以看出,Promise新建后立即执行,也就是说,Promise构造函数里的代码是同步执行的。

3. then何时执行?

看看实例:

代码语言:javascript
复制
new Promise(function(resolve, reject) {
  console.log(2)
  for (var i = 0; i < 10000; i++) {
    if(i === 10) {console.log(10)}
    i == 9999 && resolve();
  }
  console.log(3)
}).then(function() {
  console.log(4)
})

for (var i = 0; i < 5; i++) {
  console.log('a' + i);
}

结果: 2 10 3 a0 a1 a2 a3 a4 4

从结果来看,可以知道then方法指向的回调将在当前脚本所有同步任务执行完后执行。

再来回顾第一个例子:

代码语言:javascript
复制
setTimeout(function() {
  console.log(1)
}, 0);

new Promise(function(resolve, reject) {
  console.log(2)
  for (var i = 0; i < 10000; i++) {
    if(i === 10) {console.log(10)}
    i == 9999 && resolve();
  }
  console.log(3)
}).then(function() {
  console.log(4)
})

console.log(5);

结果是:2 10 3 5 4 1 通过上面的实例,相信你已经解开了三个“何时”。可能你还有一个疑惑,那就是为什么thensetTimeout执行的要早呢?

目前有两种原因导致:

1) setTimeout的0是否真的为0?

其实,setTimeout有个最小执行时间(minimum delay of 4ms ),并不是0s执行的。

注:HTML5中已经将最小执行时间统一为4ms。

2) macrotask 与 microtask

Macrotasks和Microtasks 都属于异步任务中的一种,常用api分类: macrotasks: setTimeout, setInterval, setImmediate, I/O, UI rendering microtasks: process.nextTick, Promise, MutationObserver

一个事件循环中只有一个macrotask任务,可以有一个或多个microtask任务。

来看看上面实例的执行:

  • 首先,setTimeout 被推进到 macrotask 队列(将在下一个macrotask中执行)中。
  • 接着, 会先执行 macrotask 中的第一个任务(整个 script中的同步代码 ),再加上promise 构造函数也是同步的(promise.then 回调被推进到 microtask 队列中),所以会先打印出2 10 3,然后继续执行末尾的,打印出5
  • 此时,已经执行完了第一个 macrotask , 所以接下来会顺序执行所有的 microtask, 也就是 promise.then 的回调函数,从而打印出4。
  • 此时,microtask 队列中的任务已经执行完毕,所以执行剩下的 macrotask 队列中的任务,也就是 setTimeout, 所以打印出 1.

经过层层测试,所以最终得出的结论是: 同步代码(包括promise的构造函数) -> promise.then -> setTimeout

如有错误或疑问,欢迎在下方评论区留言!

参考文章: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/EventLoop http://www.ruanyifeng.com/blog/2014/10/event-loop.html https://juejin.im/entry/5779bb0ac4c971005572ba29 https://www.zhihu.com/question/36972010/answer/71338002 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setTimeout https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ https://stackoverflow.com/questions/38752620/promise-vs-settimeout

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. setTimeout(fn, 0)何时执行?
  • 2. promise何时执行?
  • 3. then何时执行?
    • 1) setTimeout的0是否真的为0?
      • 2) macrotask 与 microtask
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档