0 喜欢

JavaScript可视化:Event Loop

admin
admin
2021-03-11 07:15:17 阅读 2808

转载自dev.to
原文作者:Lydia Hallie

JavaScript事件循环,这是每个JavaScript开发人员都必须理解的JS运行机制之一,起初理解起来可能比较混乱,我是可视化学习者,所以我想通过低分辨率的的GIF图像,从可视化的角度帮助进行解释,因为这是2019年,GIF图像可能有些像素化和模糊,凑合着看吧…

首先,事件循环是什么?我们为什么要关心呢?

JavaScript是单线程的:一次只能运行一个任务。通常这没什么问题,但是现在想象您正在运行一个耗时30s的复杂任务,是的,在这个任务进行时,我们需要等待30s才能进行其他操作(默认情况下,JavaScript在浏览器的主线程上运行,因此整个用户界面都卡住了)。到了2019年,没有人想要一个速度慢,反应迟钝的网站。幸运的是,浏览器为我们提供了JavaScript引擎本身不具备的功能:Web API。这包括DOM API, HTTP请求等,这可以帮助我们创建一些异步的,非阻塞的事件。

当我们调用一个函数时,它会被添加到被称为调用栈(call stack)的东西中。调用堆栈是JS引擎的一部分,不是特定于浏览器的,它是一个栈,意味着先入先出。当一个函数执行完,它会从堆栈中弹出。

gid1.6.gif

respond函数返回了一个setTimeout函数,setTimeout是由Web API提供给我们的:它使我们可以延迟执行任务而不会阻塞主线程。我们传递给setTimeout函数的回调函数,箭头函数() => {return “hey”}已添加到Web API。同时,setTimeout函数和response函数从堆栈中弹出,他们都返回了它们的值。

gif2.1.gif

在Web API中,计时器的运行时间与我们传递给它的第二个参数1000ms一样长,回调不会立即添加到调用堆栈中,而是会传递到队列中。

gif3.1.gif

这可能是一个令人比较困惑的部分:这并不意味着在1000ms后将回调函数添加到调用堆栈中(执行并返回一个值),它只是1000ms后添加到队列中,在队列中,回调函数必须等待轮到它。

接下来我们稍等一会…时间到了,事件循环可以执行它唯一的任务了:将队列与调用堆栈连接起来!如果调用堆栈为空,并且所有先前调用的函数都执行完毕从堆栈中弹出,则队列中的第一项将添加到调用堆栈中。这种情况下,没有其他函数被调用,这意味着回调函数成为了队列中的第一项时,此时调用堆栈为空。

gif4.gif

回调被添加到调用堆栈中,执行后并返回一个值,然后从堆栈中弹出。

gif5.gif

我们看一下下面的代码,想象一下执行后的结果。

const foo = () => console.log("First"); const bar = () => setTimeout(() => console.log("Second"), 500); const baz = () => console.log("Third"); bar(); foo(); baz();

答对了?让我们看一下在浏览器中执行这些代码时都发生了什么

gif14.1.gif

  1. 我们调用函数barbar返回了一个setTimeout函数。
  2. 我们传递给setTimeout的回调被添加到了Web API,setTimeout函数和bar函数从调用堆栈中弹出。
  3. 计时器运行,同时函数foo被调用并输出"First",函数foo返回(undefined),调用函数baz,并将回调添加到队列中。
  4. 函数baz输出"Third"。事件循环看到函数baz返回后,此时调用栈为空,然后将回调添加到调用栈中。
  5. 回调函数输出"second"。

关于作者
admin
admin
admin@ifront.net
 获得点赞 77
 文章阅读量 164426
文章标签