Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JavaScript】事件循环 Event Loop #9

Open
Tracked by #6
swiftwind0405 opened this issue Feb 25, 2020 · 0 comments
Open
Tracked by #6

【JavaScript】事件循环 Event Loop #9

swiftwind0405 opened this issue Feb 25, 2020 · 0 comments

Comments

@swiftwind0405
Copy link
Owner

swiftwind0405 commented Feb 25, 2020

执行 & 运行

JavaScript 的执行和运行是两个不同概念的,执行,一般依赖于环境,比如 node、浏览器、Ringo 等, JavaScript 在不同环境下的执行机制可能并不相同。而 Event Loop 就是 JavaScript 的一种执行方式。所以下文我们还会梳理 node 的执行方式。而运行呢,是指JavaScript 的解析引擎。这是统一的。

image

JavaScript 有一个主线程 main thread,和调用栈 call-stack 也称之为执行栈。所有的任务都会放到调用栈中等待主线程来执行。

js引擎始终只有一个线程,它维护一个消息队列,当前函数栈执行完成之后就去不断地取消息队列中的消息(回调),取到了就执行。但是js引擎只负责取消息,不负责生产消息

js运行时,就负责给js引擎线程发送消息。比如浏览器DOM事件发送一条鼠标点击的消息(浏览器子线程和js引擎线程的IPC通信),那么js引擎在执行完函数栈之后就会取到这条鼠标点击信息,执行消息(即回调);比如node运行时读取文件,执行系统调用,完成后发送读取文件完成的消息,之后的过程同上。js运行时只负责生产消息,不负责取消息

单线程

JS 是单线程的,所以需要 Event Loop 来调度。JS 是通过事件队列 (EventLoop)的方式来实现异步回调的。
DOM API / 定时器 / http 请求这些 Web API都是浏览器提供的,帮助我们实现异步 / 非阻塞的行为 。

Event Loop

image

  1. JS 在执行代码时,代码首先进入执行栈,代码中可能包含一些同步任务和异步任务。
  2. 同步任务立即执行,执行完出栈,over。
  3. 异步任务也就是常见的 ajax 请求、setTimeout 等,代码调用到这些 api 的时候,WebAPIs 来处理这些问题,执行栈继续执行。
  4. 异步任务有了运行结果时,(当 ajax 请求结果返回时),WebAPIs 把对应的回调函数放到任务队列。
  5. 执行栈为空时来读取任务队列中的第一个函数,压入执行栈。
  6. 步骤 5 不断重复,执行栈为空时,系统就去任务队列中拿第一个函数压入栈继续执行。这个过程不断重复,这就是事件循环(Event Loop)。

Event Loop 的工作就是连接任务队列和调用栈,当调用栈中的任务均执行完毕出栈,调用栈为空时,Event Loop 会检查任务队列中是否存在等待执行的任务,如果存在,则取出队列中第一个任务,放入调用栈。

宏任务和微任务

  • 宏任务 (macro-task / ES6 规范称为 task ):script(整体代码)setTimeoutsetIntervalI/OsetImmedidate(Node.js)requestAnimationFrame
  • 微任务 (micro-task / ES6 规范称为 jobs):queueMicrotaskprocess.nextTick(Node.js)MutationObserverPromise.then /catch/finally

其实也可以理解为除了微任务以外的其它任务都是宏任务

任务队列,是包括一个宏任务队列和一个微任务队列的。每次执行栈为空的时候,系统会优先处理微任务队列,处理完微任务队列里的所有任务,再去处理宏任务。

  • 在当前的微任务没有执行完成时,是不会执行下一个宏任务的。
  • 所有会进入的异步都是指的事件回调中的那部分代码。

image

注意:

  • 根据 Promise 中 then 使用方式的不同做出不同的判断,是链式还是分别调用
  • process.nextTick 优先级高于 Promise.then

queueMicrotask

为什么需要这个 api?

  • 我们应当使用底层 api 来直接完成类似的功能,而非用顶层 api 进行模拟
  • 模拟过程中,对于异常情况,会造成一些困扰,比如 Promise.resolve 会将异常转化为一个 rejected 的 Promise
  • 模拟过程中,会创建额外的对象(造成一定意义上的浪费),比如 Promise.resolve 会返回一个 Promise 实例对象,而直接 queueMicrotask 则不会
  • 除了微任务,其他类型的异步任务都有对应的 api 可供使用,比如宏任务、RAF
  • 继上一点的基础上,语义性会更好,同时帮助开发者理解这些不同异步任务之间的区别
    • `setTimeout(callback, 0)`` - 宏任务
    • requestAnimationFrame(callback) - RAF
    • queueMicrotask(callback) - 微任务

window.requestAnimationFrame(…)

Even though window.requestAnimationFrame(…) is a function of DOM object window, it’s callback is queued in a micro task queue but it’s execution strategy is different.

参考资料

@swiftwind0405 swiftwind0405 changed the title 【Day02】Event Loop 【JavaScript】Event Loop Apr 29, 2020
@swiftwind0405 swiftwind0405 changed the title 【JavaScript】Event Loop 【JavaScript】事件循环 Event Loop Jun 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant