javascript event loop

原文: https://blog.csdn.net/sjn0503/article/details/76087631html

简单来说,总体的js代码这个macrotask先执行,同步代码执行完后有microtask执行microtask,没有microtask执行下一个macrotask,如此往复循环至结束web

-----------------------------------------------------------------------面试

咱们知道 DOM 操做会触发浏览器对文档进行渲染,如修改排版规则,修改背景颜色等等,那么这类操做是如何在浏览器当中奏效的?至此咱们已经知道了事件循环是如何执行的,事件循环器会不停的检查事件队列,若是不为空,则取出队首压入执行栈执行。当一个任务执行完毕以后,事件循环器又会继续不停的检查事件队列,不过在这间,浏览器会对页面进行渲染。这就保证了用户在浏览页面的时候不会出现页面阻塞的状况,这也使 JS 动画成为可能, jQuery 动画在底层均是使用 setTimeout 和 setInterval 来进行实现。想象一下若是咱们同步的执行动画,那么咱们不会看见任何渐变的效果,浏览器会在任务执行结束以后渲染窗口。反之咱们使用异步的方法,浏览器会在每个任务执行结束以后渲染窗口,这样咱们就能看见动画的渐变效果了api

 

Several runtimes communicating together

A web worker or a cross-origin iframe has its own stack, heap, and message queue. Two distinct runtimes can only communicate through sending messages via the postMessagemethod. This method adds a message to the other runtime if the latter listens to messageevents.promise

 --------------------------------------------------------------------分割线--------------------------------------------------------------------------------浏览器

放个面试题,抛个砖:网络

console.log('start') const interval = setInterval(() => { console.log('setInterval') }, 0) setTimeout(() => { console.log('setTimeout 1') Promise.resolve() .then(() => { console.log('promise 3') }) .then(() => { console.log('promise 4') }) .then(() => { setTimeout(() => { console.log('setTimeout 2') Promise.resolve() .then(() => { console.log('promise 5') }) .then(() => { console.log('promise 6') }) .then(() => { clearInterval(interval) }) }, 0) }) }, 0) Promise.resolve() .then(() => { console.log('promise 1') }) .then(() => { console.log('promise 2') }) 

 

不着急揭晓答案,先分析app

首先知晓:webapp

js是单线程语言异步

也就是说一次就只能作一件事情。

多数的网站不须要大量计算,程序花费的时间主要集中在磁盘 I/O 和网络 I/O 上面

虽然SSD读取很快,但和CPU处理指令的速度比起来也不在一个数量级上,并且网络上一个数据包来回的时间更慢(注意过游戏的延迟吗)

so: 一些cpu直接执行的任务就成了优先执行主线任务,而后须要io返回数据的任务就成了等待被执行的任务

因此才会有同步任务(synchronous)和异步任务(asynchronous)之分

同步任务:

在主线程上排队执行的任务,前一个任务执行完毕,才能执行后一个任务;

异步任务:

不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务能够执行了,该任务才会进入主线程执行。

总之:

只要主线程空了,就会去读取”任务队列”,这就是JavaScript的运行机制

Microtasks Macrotasks

任务队列不止一个,还有 microtasks 和 macrotasks

microtasks:

  • process.nextTick
  • promise
  • Object.observe
  • MutationObserver

macrotasks:

  • setTimeout
  • setInterval
  • setImmediate
  • I/O
  • UI渲染

whatwg规范:https://html.spec.whatwg.org/multipage/webappapis.html#task-queue

  • 一个事件循环(event loop)会有一个或多个任务队列(task queue)
  • task queue 就是 macrotask queue
  • 每个 event loop 都有一个 microtask queue
  • task queue == macrotask queue != microtask queue
  • 一个任务 task 能够放入 macrotask queue 也能够放入 microtask queue 中

理解了这些定义以后,再看执行原理:

事件循环的顺序,决定了JavaScript代码的执行顺序。它从script(总体代码)开始第一次循环。以后全局上下文进入函数调用栈。直到调用栈清空(只剩全局),而后执行全部的micro-task。当全部可执行的micro-task执行完毕以后。循环再次从macro-task开始,找到其中一个任务队列执行完毕,而后再执行全部的micro-task,这样一直循环下去。

还要注意一点:

包裹在一个 script 标签中的js代码也是一个 task 确切说是 macrotask。

因此文首面试题的答案为:

start 
promise 1 
promise 2 
setInterval 
setTimeout 1 
promise 3 
promise 4 
setInterval 
setTimeout 2 
promise 5 
promise 6

简单来说,总体的js代码这个macrotask先执行,同步代码执行完后有microtask执行microtask,没有microtask执行下一个macrotask,如此往复循环至结束

相关文章
相关标签/搜索