美文网首页
js 异步全览

js 异步全览

作者: blankul | 来源:发表于2018-12-14 19:58 被阅读0次
概览

问题!

  • JS 为什么是单线程的?
  • 为什么需要异步?
  • 单线程又是如何实现异步的呢?
  • promise 的优点是什么?
  • 如何手动实现一个 Promise?
  • async 做一件什么事情?
  • await 在等什么?
  • await 等到之后,做了一件什么事情?
  • async/await 比 promise 有哪些优势?

js 是单线程的

js 是单线程的,所谓单线程,是指在 JS 引擎中负责解释和执行 JavaScript 代码的线程只有一个, 有且只有一个调用栈,每次只能做一件事, 同一时间只能做一件事,浏览器渲染和 js 共用一个线程,不妨叫它主线程。之所以设计成这样是为了避免 dom 渲染的冲突。

但是实际上还存在其他的线程。例如:处理 AJAX 请求的线程、处理 DOM 事件的线程、定时器线程、读写文件的线程(例如在 Node.js 中)等等。这些线程可能存在于 JS 引擎之内,也可能存在于 JS 引擎之外,在此我们不做区分。不妨叫它们工作线程。

但是 js 是需要异步操作的,比如 ajax 请求

通过 event loop 实现异步

为了支持异步操作,通过 event loop(事件循环,事件轮询)这种机制来实现异步
浏览器的 Event Loop 遵循的是 HTML5 标准,而 NodeJs 的 Event Loop 遵循的是 libuv。

任务队列

Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个。那么什么任务,会分到哪个队列呢?

宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering.
微任务:process.nextTick, Promise, Object.observer, MutationObserver.

浏览器的执行流程

当 call stack 空的时候,就会从任务队列中,取任务来执行。浏览器这边,共分 3 步:

取一个宏任务来执行。执行完毕后,下一步。
取一个微任务来执行,执行完毕后,再取一个微任务来执行。直到微任务队列为空,执行下一步。
更新 UI 渲染。

Event Loop 会无限循环执行上面 3 步,这就是 Event Loop 的主要控制逻辑。其中,第 3 步(更新 UI 渲染)会根据浏览器的逻辑,决定要不要马上执行更新。毕竟更新 UI 成本大,所以,一般都会比较长的时间间隔,执行一次更新。

测试

这是一道去年「今日头条」的面试题,试着看一下它的执行流程

async function async1() {
  console.log("async1 start");
  await async2();
  console.log("async1 end");
}

async function async2() {
  console.log("async2");
}

console.log("script start");

setTimeout(function() {
  console.log("setTimeout");
}, 0);

async1();

new Promise(function(resolve) {
  console.log("promise1");
  resolve();
}).then(function() {
  console.log("promise2");
});

console.log("script end");

(未完待续...)

相关文章

网友评论

      本文标题:js 异步全览

      本文链接:https://www.haomeiwen.com/subject/blknhqtx.html