博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Promise与setTimeout那些事儿
阅读量:6581 次
发布时间:2019-06-24

本文共 2165 字,大约阅读时间需要 7 分钟。

Promise与setTimeout大家应该都比较熟悉,无论是面试中还是在实际编程它们都会经常出现。面试题中经常会将二者放在一起,加些console,让你判断输出顺序,这些熟悉但是又陌生的code让人抓狂,到底顺序是啥呢?js的世界里没有偶然,没有侥幸,一切发生皆有其原由,今天让我们来一探究竟!

不多说,直接上菜:

setTimeout(() => {    // t1    console.log(1);}, 0);// t2console.log(2);var promise1 = new Promise(function (resolve, reject) {    // t3    console.log(3);    resolve(4)    setTimeout(() => {        // t5        console.log(5);    });    var promise2 = Promise.resolve().then(() => {        t6        console.log(6);    });}).then((res) => {    t4    console.log(res);});var promsie3 = Promise.resolve().then(() => {    // t7    console.log(7);});// t8console.log(8);复制代码

大家可以先在纸上写下答案,我们后面会一一拆解。这是一个大综合,看着挺复杂,其实是只纸老虎,只要我们能掌握其关键之处,便能很轻松的写出输出顺序。

首先,我们先观察题目,发现其代码类型可以分为:setTimeout,Promise,全局下的console这三部分,再细致一点其实就是同步任务与异步任务。这类问题的关键就是同步与异步任务的处理,好,让我们一一来分解。

1 javaScript事件循环

javaScript是一门单线程语言(重点),这样js事件循环就好比像是去银行窗口窗口办理业务,得排队按顺序去办理,js事件也得按照注册顺序去执行。那万一中间某一js事件执行时间很长,那是不是得一直等待吗?当然这种情况是存在的,不过我们有相应的处理方式:异步任务。例如我们浏览网页时页面发起的ajax请求,就是异步任务,这样就不阻塞主页面的浏览了。让我们用一张图来说明这个过程:

现在我们来实践一下:

1 单个异步任务

setTimeout(() => {    console.log('start');}, 0);console.log('end');// end// start复制代码
这个很简单,大家应该一目了然复制代码

2 两个相同方式的异步任务

setTimeout(() => {    // t2    console.log(0);}, 0);setTimeout(() => {    // t2    console.log(1);}, 100);// 0// 1复制代码
对于延时器来说,执行到它时就开始计时,时间结束后将回调注册到任务队列中,于是任务队列中的顺序是:t2,t1。所以输出便为0,1。复制代码

setTimeout与Promise混合在一起的时候是什么情况呢?这里我们将异步任务再细分一下:微任务,宏任务。

2 微任务与宏任务

让我们先来看看微任务与宏任务都有哪些:

  • 微任务:Promise.then、MutaionObserver、MessageChannel、process.nextTick(Node.js 环境)
  • 宏任务:script(整体代码)、setTimeout、setInterval、I/O、UI交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)

我们用一张图来说明:

在异步任务队列里微任务的优先级是高于宏任务的。在主线程任务结束后,会读取异步任务队列里的任务,判断微任务队列里是是否有任务,有的话执行。执行完毕后循环判断。直至为空,再执行宏任务队列,循环往复。

好,关键之处我们已经讲解完毕,现在让我们回头来看上面的那道‘大综合’ 让我们逐步拆解:

  • t1为宏任务,推进异步宏任务队列。
  • t2为同步任务,这里直接输出2。
  • 下面执行promise1(Promise创建后会立刻执行):执行到t3,直接输出3;执行到t5,推入到异步宏任务队列。由于二者的延时时间相等,所已t1先于t5。
  • 然后执行到promsie2,将t6推入到异步微任务队列。
  • 执行到promsie1的回调函数then,将t4推入到异步微任务队列。
  • 然后执行到promsie3,将t7推入到异步微任务队列。
  • 执行到t8,直接输出8

好,现在我们来整理下

  • 目前的输出为:2,3,8
  • 微任务队列:t6 > t4 > t7
  • 宏任务队列:t1 > t5

好,现在我们就能轻易的说出输出的值了:2,3,8,6,4,7,1,5。小伙伴们,你们做对了吗?

以上是我个人对整个过程的理解,在细节上或者一些过程上可能存在些偏差,不是很准确,仅供参考,加深理解。同学们如果发现有不对的地方,欢迎批评指正。

转载地址:http://jcino.baihongyu.com/

你可能感兴趣的文章
left join 多表关联查询
查看>>
Kali Linux的介绍
查看>>
登陆中session的处理
查看>>
Hibernate简单分页
查看>>
【技巧】使用weeman来做一个钓鱼网页
查看>>
Arcgis engine 指定图层对要素进行创建、删除等操作
查看>>
python中的Iterable, Iterator,生成器概念
查看>>
scala匿名函数
查看>>
浅析Java.lang.Runtime类
查看>>
LightGallery.js – 功能齐全的 Javascript Lightbox
查看>>
SQL Server中常用全局变量介绍
查看>>
前端学HTTP之连接管理
查看>>
WinForm 之 程序启动不显示主窗体
查看>>
ios硬件编码
查看>>
【Network】Calico, Flannel, Weave and Docker Overlay Network 各种网络模型之间的区别
查看>>
【转】Oracle索引的类型
查看>>
ActiveMQ使用示例之Topic
查看>>
FragmentTransaction.replace() 你不知道的坑
查看>>
分布式消息队列 Kafka
查看>>
模拟退火算法
查看>>