js事件循环

43次阅读

共计 685 个字符,预计需要花费 2 分钟才能阅读完成。

任务队列

  • JS 分为同步任务和异步任务
  • 同步任务都在主线程上执行,形成一个执行栈
  • 主线程之外,事件触发线程管理着一个任务队列(包括 宏任务队列 微任务队列),只要异步任务有了运行结果,就在任务队列之中放置一个事件。
  • 一旦执行栈中的所有同步任务执行完毕(此时 JS 引擎空闲),系统就会读取任务队列,将可运行的异步任务添加到可执行栈中,开始执行

宏任务

task(又称之为宏任务),可以理解是每次执行栈执行的代码就是一个宏任务。

浏览器为了能够使得 JS 内部 task 与 DOM 任务能够有序的执行,会在一个 task 执行结束后,在下一个(macro)task 执行开始前,对页面进行重新渲染

task 主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)

微任务

microtask(又称为微任务),可以理解是在当前 task 执行结束后立即执行的任务。也就是说,在当前 task 任务后,下一个 task 之前,在渲染之前。

所以它的响应速度相比 setTimeout(setTimeout 是 task)会更快,因为无需等渲染。也就是说,在某一个 macrotask 执行完后,就会将在它执行期间产生的所有 microtask 都执行完毕(在渲染前)。

microtask 主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)

执行顺序

  1. 清空执行栈
  2. 清空微任务队列
  3. 取出一个宏任务队列里的事件,在执行栈执行
  4. 重复上面 2、3
  5. 等待
正文完
 0

js事件循环

43次阅读

共计 1139 个字符,预计需要花费 3 分钟才能阅读完成。

console.log('begin');
setTimeout(function() {console.log('timeout') });
new Promise(function(resolve) {for (let i = 0; i < 3; i++) {if (i == 1) resolve();
        console.log(i);
    }
    console.log('promise')
}).then(function() {console.log('then')
})
console.log('end');

上述代码依次输出:begin、0、1、2、promise、end、then、timeout

js 的一个特点就是单线程,但是很多时候我们仍然需要在不同的时间去执行不同的任务,例如给元素添加点击事件,设置一个定时器,或者发起 ajax 请求,因此需要一个异步机制来达到这样的目的,事件循环机制也因此而来。

每一个 js 程序都拥有唯一的事件循环,大多数代码的执行顺序是可以根据函数调用栈的规则执行的,而 setTimeout/setInterval 或者不同的事件绑定(click、mousedown 等)中的代码,则通过队列来执行。

任务队列又分为宏任务(macro-task)与微任务(micro-task)两种,在浏览器中,包括:

  • macro-task:script(整体代码)、setTimeout/setInterval、I/O、UI rendering 等
  • micro-task:Promise

事件循环的顺序,决定了 js 代码的执行顺序:
首先从 macro-task 中的 script 开始第一次循环。此时全局上下文进入函数调用栈,直到调用栈清空,在这个过程中,如果遇到任务分发器(例如 timer、promise),就会将任务放入对应队列中去

第一次循环时,macro-task 中其实只有 script,因此函数调用栈清空之后,会直接执行所有的 micro-task。当所有可执行的 micro-task 执行完毕之后,就表示第一次事件循环结束

第二次循环会再次从 macro-task 开始执行。此时 macro-task 中的 script 队列已经没有任务了,但是可能会有其他的队列任务,而 micro-task 中暂时还没有任务。此时会先选择其中一个宏任务队列,例如 setTimeout,将该队列中所有的任务全部执行完毕,然后再执行此过程中可能产生的微任务。微任务执行完毕之后,再回过头来执行其他宏任务队列中的任务。以此类推,直到所有宏任务队列中的任务都被执行了,并且清空了微任务,第二次循环就会结束

如果在第二次循环过程中,产生了新的宏任务队列,或者之前宏任务队列中的任务暂时没有满足执行条件,例如延迟时间不够或者事件没有被触发,那么将会继续以同样的顺序重复循环

正文完
 0