资讯专栏INFORMATION COLUMN

Event Loop 其实也就这点事

PrototypeZ / 2266人阅读

摘要:众所周知,是,也就意味着在执行的过程中,是,而这样的特性,正是由一个叫的东西决定的有且仅有一个。无论从工程效率还是用户体验的角度来说,这都是不被允许的一件事情。五秒后,结束计时,将回调函数下放到中。至此,正式引出的概念。

前段时间在网上陆续看了很多关于 Event loop 的文章,看完也就混个眼熟,可能内心深处对这种偏原理的知识有一些抵触心情,看完后也都没有去深入理解。最近在看 Vue 的源码,在读到关于 nextTick 的实现时,总有一种似曾相识的感觉,于是去网上查了下资料,原来 nextTick 的实现正是基于 Event loop 机制(引起重视了)。
Anyway,在翻阅了一些资料以后,将我对 Event loop 的理解记录下来,爱看不看。

Call Stack

众所周知,JavaScript 是 one-threaded,也就意味着在执行 JavaScript 的过程中,是 One thing at a time,而这样的特性,正是由一个叫 Call Stack 的东西决定的(有且仅有一个)。
既然是栈,就满足 FILO 的原则。故 Call Stack 在函数运行时的表现为:

当有函数执行时,该函数被 push 到 Call Stack

当函数执行结束时,该函数从 Call Stack 内被 pop 出

如果函数内有调用到其他函数(执行结束前),则将其他函数再 push 到 Call Stack 中,等到调用结束时 pop 出

由此可见,如果一个函数定义如下:

const dead = () => {
    return dead();
}

那么当其被执行时,就会向 Call Stack 中不断的 push 同一个函数(dead),导致整个页面挂掉。

When Call Stack Meets Sync Request

众所又周知了,在 jQuery 提供的 Ajax 函数中,可供开发者选择请求是 sync 还是 async,我们先讨论 Call Stack 遇到 sync 请求时会发生什么。

const name = $.ajaxSync(URL_1);
const info = $.ajaxSync(URL_2);
const work = $.ajaxSync(URL_3);

console.log(name);
console.log(info);
console.log(work);

屋漏偏逢连阴雨,此时的网络状态又极差,每一个网络请求从发出到成功要经历五秒,想象一下上面这段代码如果跑起来了,会发生什么?
这是一件让人绝望的事情:
随着程序的推进,ajaxSync 函数会先后三次被 push 并 pop 出 Call Stack,而每一次从 push 到 pop 的过程需要耗费五秒钟的时间。
无论从工程效率还是用户体验的角度来说,这都是不被允许的一件事情。

Async & Callback

为了杜绝上面的问题,浏览器提供给了开发者一个叫做异步 + Callback 的解决方案。先看一段代码:

console.log("kyrieliu");

setTimeout(function(){
    console.log("about Event Loop");
}, 5000);

console.log(" is writing an article ");

运行结果显而易见。
ok,那么这段代码在 Call Stack 中的表现又是怎样的呢?
基于上面文章所述,我推测:
首先,第一行代码入栈,执行完毕后出栈;紧接着,setTimeout 入栈,然后emmm,事情有点不对劲了:如果 setTimeout 入栈执行后立刻出栈,那么它内部的 console 为什么五秒后才打印出来?

Task Queue

问题的关键,是一个叫做 Task Queue 的东西。
紧接着刚才的步骤:setTimeout入栈后执行并触发了一个五秒的 timer,这个 timer 由 Web api 维护,至此,setTimeout执行完毕并出栈,第三个 console 入栈执行并出栈。五秒后,timer 结束计时,将回调函数 callback 下放到 task queue 中。
但 callback 还未执行,它什么时候执行呢?Call Stack 为空的时候。
此时的 call stack 已经为空,所以 callback 被 push 进栈执行并 pop 出,这样一来就解释得通了。
至此,正式引出 Event Loop 的概念。

Event Loop

If the call stack is clear and there"s something in the task queue, push the first thing on the queue onto the stack.

setTimeout(callback, 0)

在最开始接触 JavaScript 的时候,看到上面这行代码的我是懵蔽的,0ms 后执行 callback, WTF?
在了解了 Event Loop 的运行机制后,再回过头来尝试解释一下这行代码,即:在 setTimeout 入栈执行时,内部的 callback 会立即被下放到 task queue 中,但它无法执行,因为此时的 call stack 不为空,等到 call stack 为空时,callback 才得以执行。

Thanks

Philip Roberts: Help, I’m stuck in an event-loop.

A super-cool demo of Event Loop

广而告之
个人公众号,不止于前端

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97298.html

相关文章

  • 浏览器与Node的件循环(Event Loop)有何区别?

    摘要:事件触发线程主要负责将准备好的事件交给引擎线程执行。它将不同的任务分配给不同的线程,形成一个事件循环,以异步的方式将任务的执行结果返回给引擎。 Fundebug经作者浪里行舟授权首发,未经同意请勿转载。 前言 本文我们将会介绍 JS 实现异步的原理,并且了解了在浏览器和 Node 中 Event Loop 其实是不相同的。 一、线程与进程 1. 概念 我们经常说 JS 是单线程执行的,...

    TANKING 评论0 收藏0
  • event loop 与 vue

    摘要:但是导致了很明显的性能问题。上述两个例子其实是在这个中找到的,第一个使用的版本是,这个版本的实现是采用了,而后因为的里的有,于是尤雨溪更改了实现,换成了,也就是后一个所使用的。后来尤雨溪了解到是将回调放入的队列。 结论 对于event loop 可以抽象成一段简单的代码表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...

    springDevBird 评论0 收藏0
  • event loop 与 vue

    摘要:但是导致了很明显的性能问题。上述两个例子其实是在这个中找到的,第一个使用的版本是,这个版本的实现是采用了,而后因为的里的有,于是尤雨溪更改了实现,换成了,也就是后一个所使用的。后来尤雨溪了解到是将回调放入的队列。 结论 对于event loop 可以抽象成一段简单的代码表示 for (macroTask of macroTaskQueue) { // 1. Handle cur...

    Barry_Ng 评论0 收藏0
  • 细说JavaScript单线程的一些

    摘要:标签单线程首发地址码农网细说单线程的一些事最近被同学问道单线程的一些事,我竟回答不上。若以多线程的方式操作这些,则可能出现操作的冲突。另外,因为是单线程的,在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务执行。 标签: JavaScript 单线程 首发地址:码农网《细说JavaScript单线程的一些事》 最近被同学问道 JavaScript 单线程的一些事,我竟回答不上。好...

    sarva 评论0 收藏0
  • 细说JavaScript单线程的一些

    摘要:标签单线程首发地址码农网细说单线程的一些事最近被同学问道单线程的一些事,我竟回答不上。若以多线程的方式操作这些,则可能出现操作的冲突。另外,因为是单线程的,在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务执行。 标签: JavaScript 单线程 首发地址:码农网《细说JavaScript单线程的一些事》 最近被同学问道 JavaScript 单线程的一些事,我竟回答不上。好...

    coolpail 评论0 收藏0

发表评论

0条评论

PrototypeZ

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<