美文网首页让前端飞Web前端之路程序员
javascript异步队列Microtasks Macrota

javascript异步队列Microtasks Macrota

作者: kuulid | 来源:发表于2017-11-19 17:23 被阅读119次

看来看一段代码:

console.log('start');

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

setTimeout(function() {
    console.log('settimeout2');
    Promise.resolve()
    .then(function() {
        console.log('Promise3');
    })
    .then(function() {
        console.log('Promise4');
    })
}, 0);


Promise.resolve()
.then(function() {
    console.log('Promise1');
})
.then(function() {
    console.log('Promise2');
})

我们知道,js的的执行机制是事件队列,即task queue,所有异步的操作都会放到下一个task queue中,不管是游览器还是node。但通过运行上面代码,似乎发现不同的异步事件放入task queue中有先后顺序。
没错,不同的异步任务也有所不同:

  • macrotasks: setTimeout setInterval setImmediate I/O UI渲染
  • microtasks: Promise process.nextTick Object.observe MutationObserver

每一个事件队列中包含macrotasks和microtasks,每一个task queue都从一个macrotasks开始执行,然后执行放入这个queue中的所有microtasks,大致如下:


image.png

可以看出
task queue == macrotask queue != microtask queue
所以照此来分析上面代码,不难得到答案,
任务队列1:

console.log('start');
Promise.resolve()
.then(function() {
    console.log('Promise1');
})
.then(function() {
    console.log('Promise2');
})

执行完macrotasks,再把队列的microtasks都执行完。
任务队列2:

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

任务队列3

setTimeout(function() {
    console.log('settimeout2');
    Promise.resolve()
    .then(function() {
        console.log('Promise3');
    })
    .then(function() {
        console.log('Promise4');
    })
}, 0);

执行完settimeout2执行Promise3,Promise4。
最后输出:

start
Promise1
Promise2
settimeout1
settimeout2
Promise3
Promise4

macrotasks和microtasks最大的不同的是:当 macrotasks 出队时,任务是一个一个执行的;而microtasks 出队时,任务是一队一队执行的。也就是说microtasks的队列一次一定会执行完,利用这个特性,很多框架实现了批量更新render,比如vue的nextTick,查看源码

export function nextTick (cb?: Function, ctx?: Object) {
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, 'nextTick')
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })
  // 检查上一个异步任务队列(即名为callbacks的任务数组)是否派发和执行完毕了。pending此处相当于一个锁
  if (!pending) {
    // 若上一个异步任务队列已经执行完毕,则将pending设定为true(把锁锁上)
    pending = true
    // 是否要求一定要派发为macro任务
    if (useMacroTask) {
      macroTimerFunc()
    } else {
      // 如果不说明一定要macro 你们就全都是micro
      microTimerFunc()
    }
  }
  // $flow-disable-line
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

可以看到,利用promise来包装成microtasks,将改变批量执行完。

相关文章

  • javascript异步队列Microtasks Macrota

    看来看一段代码: 我们知道,js的的执行机制是事件队列,即task queue,所有异步的操作都会放到下一个tas...

  • JavaScript事件循环

    Tasks(任务),microtasks(微任务),queues(队列),schedules(调度): 举个例子:...

  • 问题点整理发布列表(未完待续...)

    1,JavaScript异步队列问题 https://juejin.im/post/59cce3675188250...

  • JavaScript事件循环机制

    JavaScript单线程执行 同步栈执行完成后,再执行异步队列 异步队列中分为宏任务和微任务 微任务比宏任务优先...

  • GCD基础总结一

    上代码~ 同步串行队列 同步并行队列 异步串行队列 异步并行队列 主队列同步 会卡住 主队列异步

  • js笔记

    Javascript 事件循环: js解析方法时,将同步任务排队到执行栈中,异步任务排队到事件队列中。 事件队列分...

  • GCD的几种创建方式及基本使用

    同步函数 同步函数+主队列 同步函数+串行队列 同步函数+并发队列 异步函数 异步函数+主队列 异步函数+串行队列...

  • GCD队列、同步异步

    GCD队列、同步异步 GCD队列、同步异步

  • javascript任务队列异步函数

    下面这段代码输出结果是? 为什么? 先输出1,再输出3,最后输出2解释 初始化运行时,主线程会去执行所有的同步任务...

  • event loop

    javascript是单线程的 任务队列 所有的任务分为同步任务和异步任务,同步任务是在主线程上排队执行的,异步任...

网友评论

    本文标题:javascript异步队列Microtasks Macrota

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