从event loop出发讨论Promise、setTimeout的执行顺序

***

Event Loop 这个概念相信大家或多或少都了解过,所谓温故而知新,so,今天,我们就从event loop出发,看看在事件的执行过程中,他都经历了些什么。

#### 什么是event loop

event loop是js的事件执行机制,我们一般简称为事件循环(之所以称作事件循环,是因为它经常被用于类似如下的方式来实现)

```javascript

while (queue.waitForMessage()) {

            queue.processNextMessage();

            }

```

      如果当前没有任何消息`queue.waitForMessage` 会等待同步消息到达,当完成当前任务后,继续去查看有无需要执行的任务如果需要执行,就再次执行,如此循环,所以称之为事件循环。

#### 同步和异步任务

      要了解异步线程我们首先应该明白它的用处,因为js的`单线程`特性,任务的执行顺序都是依次执行,而当我们在工作中遇到网络请求,前后端交互的时候,你的数据不会马上拿到,这需要时间,如果等拿到数据再执行下面的代码,这样如果多次请求就会发现加载速度极慢,这样显然不合理,这样就会出现很多次的暂停等待,所以这时候 需要执行异步任务,当我们发起请求时候,采用异步的方式,浏览器检测到其为异步时,就会开辟一个新的进程处理该函数,然后继续执行后面的任务,当完成了执行栈里的同步任务之后,再检测是否有异步任务需要执行,最后执行异步任务。

```javascript

-同步任务进入主线程,按顺序从上而下依次执行,

-异步任务,进入`event table` ,注册回调函数 `callback` ,

任务完成后,将`callback`移入`event queue`中等待主线程调用

```

#### 异步任务分为微任务和宏任务

      在执行过程中,我们知道了同步任务会优先异步任务执行,那么在异步中呢,异步中同样包含微任务和宏任务,首先我们大概了解下微任务和宏任务,在js中:

* 微任务(micor Task) :promise  MutationObserver process.nextTick

* 宏任务(macro Task):script settimeout setinterval setImmediate requestAnimationFrame

> 宏任务

>

> | #                    | 浏览器 | node |

> | --------------------- | :----: | :--: |

> | I/O                  |  √    |  √  |

> | setTimeOut            |  √    |  √  |

> | setInterval          |  √    |  √  |

> | setImmediate          |  ×    |  √  |

> | requestAnimationFrame |  √    |  ×  |

>

> 微任务

>

> | #                          | 浏览器 | node |

> | -------------------------- | :----: | :--: |

> | process.nextTick          |  ×    |  √  |

> | MutationObserver          |  √    |  ×  |

> | Promise.then catch finally |  √    |  √  |

这两种任务在不同环境下支持的各不同,今天我们主要看看在浏览器中,我们经常会遇到的有 `promise` 和 `setTimeout` 我们通过下面这段代码来看看:

```javascript

    console.log(1)


    setTimeout(() => console.log(2), 0)


    new Promise((resolve, reject) => {

        console.log(3)

        resolve()

    }).then(() => {

        console.log(4)

    })

```

首先来分析下,这段代码中包含同步任务,包含异步的宏任务`setTimeout`,包含异步的微任务`promise`,这套题的答案是1.3.4.2 ,我们首先找到同步任务,1 3 是同步任务,然后执行异步任务,异步任务如果按顺序执行则是24  但是答案是4.2那么我们可以知道 promise的执行顺序优先于setTimeout所以由此可知,在异步任务中,微任务优先于宏任务执行,可以看看下图。

`红线就是任务的执行顺序`

`黑线是任务的结构`

看完这么多下面来完成下面这道题并加以分析:

```javascript

console.log(1)

setTimeout(() => {

    console.log(2)

    new Promise((resolve, reject) => {

        console.log(3)

        resolve()

    }).then(() => {

        console.log(4)

    })

}, 0)

new Promise((resolve, reject) => {

    console.log(5)

    resolve()

}).then(() => {

    console.log(6)

})

setTimeout(() => {

    console.log(7)

    new Promise((resolve, reject) => {

        console.log(8)

        resolve()

    }).then(() => {

        console.log(9)

    })

}, 0)

console.log(10)

const promise = new Promise((resolve, reject) => {

    console.log(1);

    console.log(2);

  });

  promise.then(() => {

    console.log(3);

  });

  console.log(4);

```

> 答案:`1 , 5 , 10 , 6 , 2 , 3 , 4 , 7 , 8 , 9`

  废话不多说直接解题

+ 进入主线程开始执行, 遇到 `console.log(1)`, 输出 `1`

+  遇到一个 `setTimeout` 宏任务, 将其回调函数推入 `macro Task` 的 `event queue` 中,`macro Task` 的 `event queue` 中记一个任务 `setTimeout1`

+ 然后碰到 `promise` 微任务, 直接执行 `new Promise` 输出 `5`, 并将 `then` 函数的回调函数推入 `micro Task` 的 `event queue` 中, `micro Task` 的 `event queue` 中记 一个 微任务 `promise1`

+ 又遇到了 `setTimeout` 宏任务, 同理,将其回调函数推入 `macro Task` 的 `event queue` 中,`macro Task` 的 `event queue` 中记一个任务 `setTimeout2`

+ 最后,执行 `console.log(10)`, 输出 10

> 上一轮事件循环结束,我们发现,已经输出 `1 5 10` 了, 按照我们之前所说,这个时候,主线程会去检查 是否存在微任务,不难发现,这个时候的 `event queue` 是这个样子的

| **micro Task (微任务)** | **macro Task(宏任务)** |

| :---------------------: | :--------------------: |

|        promise1        |      setTimeout1      |

|                        |      setTimeout2      |

```javascript

主线程 ---> promis1 ---> settimeout1 ---> settimeou2 ---> 循环检查主线程任务栈是否还有任务

```

#### 结语

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容