首页 > 技术文章 > Promise从入门到放弃

LqZww 2020-09-18 00:22 原文

Event Loop

在讲解 Promise 之前,我们先来了解下 Event Loop(事件循环 / 事件轮询)。

我们都知道 JavaScript 是单线程的,单线程也就意味着所有的任务都需要排队,只有当前一个任务结束后,才会去执行后一个任务。如果前一个任务所耗时长很久,就容易导致后面的任务堵塞。

我们可以把这些任务分为两类,即 同步任务异步任务

  1. 同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕后,才能执行后面一个任务;
  2. 异步任务:不进入主线程、而进入 "任务队列" 的任务,只有 "任务队列" 通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。

JavaScript 执行步骤:

  1. 从前到后,依次执行;
  2. 如果某一行报错,后面的代码将不会执行;
  3. 先执行同步任务,再执行异步任务。

我们先来看如下代码,执行顺序是怎样的呢:

console.log(1);

setTimeout(function fn() {
  console.log(2);
}, 5000)

console.log(3);

是不是很简单,执行结果为:1 3 2。

下面我们就上面这个例子来讲解一下 event loop 的执行过程。

我们可以在 latentflip.com/loupe 这个网站查看具体的执行过程。

我们先来看如下图每个区域的含义:

再来看看具体的执行过程:

  1. console.log(1) 放进 Call Stack 后执行打印出 1,然后退出;
  2. 将 setTimeout 放进 Call Stack 后,然后把 fn() 放进 Web Apis 里后 setTimeout 退出;
  3. console.log(3) 放进 Call Stack 后执行打印出 3,然后退出;
  4. 此时所有同步代码已经执行完毕,Call Stack 里不会再有代码进入,然后进行 event loop 机制,它会一遍又一遍的进行循环,从 Callback Quese 里去找有没有函数,如果有就放入 Call Stack 里去执行;
  5. 当 fn() 在 Web Apis 里呆了 5s 后会自动进入 Callback Quese 里;
  6. 此时 event loop 会发现 Callback Quese 里有个 fn(),会立刻把 fn() 推到 Call Stack 里,并立即触发 fn() 的执行;
  7. 然后把 console.log(2) 放进 Call Stack 后执行打印出 2,然后退出;
  8. 最后退出 fn(),清空 Call Stack。

下面我们简洁的总结下上面的执行过程:

  1. 把同步代码一行一行的放进 Call Stack 里去执行;
  2. 如果遇到异步代码,会放到 Web Apis 里记录一下,并且等待时机成熟后放进 Callback Quese 里;
  3. 如果同步代码执行完后(即 Call Stack 为空),event loop 就可以开始上班了;
  4. 循环查找 Callback Quese,如有则移动至 Call Stack 里去执行,然后再继续循环查找(找呀找呀找

推荐阅读