专栏首页码力全开动图学 JavaScript 之:事件循环(Event Loop)

动图学 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) 的特点。当一个函数调用完成,它就被从调用栈中弹出。

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

任务队列

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

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

事件循环

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

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

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

一个例子

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

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

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

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

本文是翻译的系列文章:

参考文章

本文分享自微信公众号 - 码力全开(codingonfire),作者:savokiss

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 浅析 FP:JavaScript 中的纯函数

    纯函数 是一个常见的概念,在日常工作中也经常会遇到,它其实非常简单,今天我们来了解一下它的好处以及为什么要使用它。

    savokiss
  • 动图学 JavaScript 之:声明提升(Hoisting)

    JS 由于语言设计的缺陷(工期不够?),里面有一些堪称神奇的特性,初学者碰到后可能会满脸黑人问号,今天要介绍的就是其中的一个特性:声明提升(Hoisting)。

    savokiss
  • 浅析 JS 事件循环之 Microtask 和 Macrotask

    我们在上一篇 《浅析 JS 中的EventLoop 事件循环》 中提到一个 Event Queue,其实在事件循环中 queue 一共有两种,还有一种叫 Job...

    savokiss
  • 《Go语言程序设计》读书笔记(二)函数

    《Go 语言程序设计》在线阅读地址:https://yar999.gitbooks.io/gopl-zh/content/

    KevinYan
  • Python: 函数式编程

    map()函数接收两个参数,一个是函数,一个是序列,map将传入的函数依次作用到序列的每个元素,并把结果作为新的list返回,比循环更简洁,更易读。

    用户2183996
  • python学习笔记 函数

    在python中,函数是一等对象。编程语言理论家把“一等对象”定义为满足以下条件的程序实体:

    py3study
  • 一键抠图,毛发毕现:这个GitHub项目助你快速PS

    抠图是 PS 中的一项常用技术。但是要做到完美地将图像中的目标选取出来往往费时费力。近日,一个名为 PyMatting 的项目无疑能够帮助你。

    CV君
  • 一键抠图,毛发毕现:这个GitHub项目助你快速PS

    抠图是 PS 中的一项常用技术。但是要做到完美地将图像中的目标选取出来往往费时费力。近日,一个名为 PyMatting 的项目无疑能够帮助你。

    机器之心
  • Python高阶函数

    函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计...

    小破孩的梦想空间
  • 回溯法解数独

    数独,是源自18世纪瑞士的一种数学游戏,是一种运用纸、笔进行演算的逻辑游戏。玩家需要根据9×9盘面上的已知数字,推理出所有剩余空格的数字,并满足每一行、每一列、...

    孟君

扫码关注云+社区

领取腾讯云代金券