动图学 JavaScript 之:事件循环(Event Loop)

前言

今天该学习 Event Loop 啦,其实之前我写过一篇 Event Loop 的文章:

浅析 JS 中的 EventLoop 事件循环(新手向)

这篇呢则是动图学 JS 系列中的,可以结合之前的文章食用~

我们都知道 JavaScript 是一门 单线程 的语言:同一时间只能运行一个任务。通常情况下这没什么问题,但是如果你有一个任务需要耗费 30 秒的时间,那其他任务难道都要等它 30 秒么?(由于 JS 运行在浏览器的主线程,所以这 30 秒的时间里,整个页面都会处于卡死状态)

幸运的是,浏览器提供了一些 JS 引擎不具备的功能:Web API。它包括 DOM APIsetTimeoutHTTP 请求 等等。这些功能都可以帮助我们处理 异步、非阻塞 的操作。

调用栈

当我们调用一个函数时,它会被添加到一个叫做 调用栈 (call stack) 的地方,调用栈是 JS 引擎的一部分,而不是浏览器特有的。本质上它是一个栈,具有 后进先出 (Last In, First Out. 即 LIFO) 的特点。当一个函数调用完成,它就被从调用栈中弹出。

1-call-stack.gif

上图中函数 respond 返回了一个 setTimeout 函数,它也被添加到调用栈中,(setTimeout 正是 Web API 提供的功能之一:它可以让我们延迟一个任务的执行并且不阻塞主线程。)setTimeout 被调用之后,传给它的箭头函数 () => { return 'Hey' } 就被添加进了 Web API (此处简化了概念,具体可以看笔者的另一篇文章)中。同时 setTimeoutrespond 函数从调用栈中弹出,它们都返回了相应的值。

2-setTimeout.gif

任务队列

在 Web API 中,一个定时器已经创建,它将会等待 1000 ms,当时间到后,这个箭头函数并不会立即被调用栈执行,它会被添加到一个队列中,我们暂且称之为 任务队列 (原文中叫 Callback Queue)。

3-task-queue.gif

这里可能会让人困惑:那个回调箭头函数并不是在 1000ms 后被直接添加到 调用栈 的,而是被添加进了 任务队列。队列嘛,就是大家排队,先来的先服务,被谁服务?没错!就是调用栈。

事件循环

说了这么多,终于轮到我们的 Event Loop 登场了!如果上面的调用栈是一个银行窗口,任务队列中的回调函数是一个个排队办业务的人,那么 Event Loop 就是叫号系统!Event Loop 的唯一任务就是 连接任务队列和调用栈

它不停检查 调用栈 中是否有任务需要执行,如果没有,就检查 任务队列,从中弹出一个任务,放入调用栈中,如此往复循环。

4-event-loop.gif

上图中终于轮到那个箭头函数接受调用了,它被调用完,也被弹出了,轻轻地它走了,只留下一个 Hey! o(╯□╰)o

5-arrow-called.gif

一个例子

看图片是不是挺好理解的~ 那就来看一个例子,可以把下面的代码粘贴到浏览器的控制台亲自跑一下:

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

bar();
foo();
baz();

6-example.gif

  1. 我们调用了函数 barbar 返回了一个 setTimeout 函数。
  2. setTimeout 中的回调函数被添加到 Web APIsetTimeout 函数和 bar 调用完成被从调用栈弹出。
  3. 定时器开始,同时函数 foo 被调用,打印出 Firstfoo 函数返回 undefined
  4. 函数 baz 被调用,打印出 Third
  5. 500ms 定时器结束,回调函数被放入任务队列,Event Loop 检查到调用栈是空的,所以将其取出放在调用栈。
  6. 回调函数被执行,打印出 Second

全文就到这里啦,希望对你理解 Event Loop 有所帮助~

本文是翻译的系列文章:


本文首发于公众号:码力全开(codingonfire)

本文随意转载哈,注明原文链接即可,公号文章转载联系我开白名单就好~

codingonfire.jpg

参考文章


码力全开
尽我所能为大家带来有用的东西~ 欢迎关注公众号:「码力全开」

You know nothing, SpongeBob.

6.2k 声望
4.5k 粉丝
0 条评论
推荐阅读
如何批量 git pull 某个文件夹中的 git 仓库?
上代码用 shell 脚本可以比较方便实现:首先新建脚本:pull-all.sh {代码...} 填入如下内容: {代码...} 然后改一下权限: {代码...} 接下来就可以直接运行了: {代码...} 也可以不跟参数,会提示你输入目录~注意...

savokiss阅读 1.5k

封面图
手把手教你写一份优质的前端技术简历
不知不觉一年一度的秋招又来了,你收获了哪些大厂的面试邀约,又拿了多少offer呢?你身边是不是有挺多人技术比你差,但是却拿到了很多大厂的offer呢?其实,要想面试拿offer,首先要过得了简历那一关。如果一份简...

tonychen152阅读 17.7k评论 5

封面图
正则表达式实例
收集在业务中经常使用的正则表达式实例,方便以后进行查找,减少工作量。常用正则表达式实例1. 校验基本日期格式 {代码...} {代码...} 2. 校验密码强度密码的强度必须是包含大小写字母和数字的组合,不能使用特殊...

寒青56阅读 8.5k评论 11

JavaScript有用的代码片段和trick
平时工作过程中可以用到的实用代码集棉。判断对象否为空 {代码...} 浮点数取整 {代码...} 注意:前三种方法只适用于32个位整数,对于负数的处理上和Math.floor是不同的。 {代码...} 生成6位数字验证码 {代码...} ...

jenemy48阅读 7k评论 12

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木75阅读 7.1k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs42阅读 6.8k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木45阅读 8.5k评论 6

You know nothing, SpongeBob.

6.2k 声望
4.5k 粉丝
宣传栏