美文网首页
JS浏览器事件循环和任务队列

JS浏览器事件循环和任务队列

作者: 无脚鸟30 | 来源:发表于2019-05-26 22:52 被阅读0次

    JS的异步机制由事件循环和任务队列构成。JS本身是单线程语言,所谓异步依赖于浏览器或者操作系统等完成。JavaScript主线程拥有一个执行栈以及一个任务队列,主线程会依次执行代码,当遇到函数时,会先将函数入栈,函数运行完毕后再将该函数出栈,直到所有代码执行完毕。

    遇到异步操作(例如:setTimeout, AJAX)时,异步操作会由浏览器(OS)执行,浏览器会在这些任务完成后,将事先定义的回调函数推入主线程的任务队列(task queue)中,当主线程的执行栈清空之后会读取task queue中的回调函数,当task queue被读取完毕之后,主线程接着执行,从而进入一个无限的循环,这就是事件循环.

    Microtask 与 Macrotask

    一个浏览器环境只能拥有一个事件循环(event loop),而一个事件循环可以多个任务队列(Task queue),每个任务都有一个任务源(Task source)。任务队列是一个先进先出的队列.

    macrotask(macro-task: script(整体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering) 和 microtask(micro-task: process.nextTick, Promises(这里指浏览器实现的原生 Promise), Object.observe, MutationObserver) 是异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。

    全部代码(script)是一个macrotask, js先执行一个macrotask,执行过程中遇到(setTimeout, setInterval, setImmediate等)异步操作则创建一个macrotask,遇到(process.nextTick, Promises等)创建一个microtask, 这两个queue分别被挂起. 执行栈为空时开始处理macrotask, 完成后处理microtask, 直到该microtask全部执行完,然后继续主线程调用栈.

    每一次事件循环(one cycle of the event loop),只处理一个macrotask。待该 macrotask 完成后,所有的 microtask 会在同一次循环中处理。处理这些 microtask 时,还可以将更多的 microtask 入队,它们会一一执行,直到整个microtask队列处理完。

    主要流程如下:

    1. 所有同步任务都在主线程上执行,形成一个执行栈

    2. 主线程之外,还存在一个任务队列只要异步任务有了运行结果,就在任务队列之中放置一个任务。

    3. 一旦执行栈中的所有同步任务执行完毕,系统就会读取任务队列,看看里面有哪些任务。那些对应的异步任务,就结束等待状态,进入执行栈开始被执行。

    4. 主线程不断重复以上三步。

    js引擎存在monitoring process进程,会持续不断的检查主线程执行栈是否为空,一旦为空,就会去task queue那里检查是否有等待被调用的函数。

    事件循环和任务队列

    相关文章

      网友评论

          本文标题:JS浏览器事件循环和任务队列

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