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

前言

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

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

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

咱们都知道 JavaScript 是一门 单线程 的语言:同一时间只能运行一个任务。一般状况下这没什么问题,可是若是你有一个任务须要耗费 30 秒的时间,那其余任务难道都要等它 30 秒么?(因为 JS 运行在浏览器的主线程,因此这 30 秒的时间里,整个页面都会处于卡死状态)segmentfault

幸运的是,浏览器提供了一些 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)。oop

3-task-queue.gif

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

事件循环

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

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

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

参考文章

相关文章
相关标签/搜索