JS中事件循环中的任务队列(macrotask microtask)

前言

最近已经开始在老项目中使用ES6编写代码,从ES6原生的模块导入到方便的模板字符串、解构赋值都给开发页面带来了不一样的感觉。当然还有await,async的出现彻底解决了javascript异步事件模型带来的困扰,本文用图文来解释javascript事件循环中存在的各个任务队列,更进一步理解事件循环。(本文需要对js事件循环有一定基础)

Promise对象

299425.png

这是一张js执行时示意图,上图中,主线程运行的时候,产生堆(heap)和栈(stack),栈中的代码调用各种外部API,它们在"任务队列"中加入各种事件(click,load,done)。只要栈中的代码执行完毕,主线程就会去读取"任务队列",依次执行那些事件所对应的回调函数。 在ES5年代,我们要添加往任务队列里面添加事件回调,常用的手段就是setTimeout,ajax等 如这段代码,无论执行多少次,输出的结果一定是10,理由见图

var number = 10;
setTimeout(function(){// 加入任务队列里面的
    number = 20;
})
console.log(num); //10

在es6中,加入了一个新的对象promise,使得我们可以使用promise将事件回调加入任务队列中,如

let number = 10;
new Promise((resolve)=>{
    number = 30;
    resolve();   
})
    .then(()=>{ // 加入任务队列里面的
        number=20;
    })
console.log(number); // 30

macrotask与microtask

刚才说到,一般情况,我们要往任务队列里面加入事件回调,一般可以通过setTimeout以及Promise对象的then方法,那么他们有什么区别呢?看一下下面的代码

var number = 10;
setTimeout(()=>{
   number+=10; // 20+=10
   console.log(number);  //30
})
new Promise((resolve)=>resolve()).then(()=>{
   number = 20;
   console.log(number); // 20
})

setTimeout中的log以及then中的log分别会打印30以及20,无论调用多少次,promise中的then总是会先执行,把他们的执行顺序更换后也是一样的。

var number = 10;
new Promise((resolve)=>resolve()).then(()=>{
   number = 20;
   console.log(number); // 20
})
setTimeout(()=>{
   number+=10; // 20+=10
   console.log(number);  //30
})

为什么会出现这样的现象?这就要从JS中两种不同的任务队列说起,我们知道,在事件循环中,当主线程任务栈执行完成后,会读取任务队列依次执行,任务队列在其中分为两种macrotask && microtask,这两种队列会因为不同的api来生成,具体如下

macrotasks: setTimeout setInterval setImmediate I/O UI渲染

microtasks: Promise process.nextTick Object.observe MutationObserver

那么,他们有什么区别呢?我们来看看一个完整的js执行流程

  1. 检查macrotask队列,选择其中最早加入(即最老的)的任务X,设置为“目前运行的任务”。如果任务X不存在,那么直接跳到步骤4。

  2. 运行任务X,即运行对应的回调函数。

  3. 设置“目前运行的任务”为null,从macrotask队列中移除任务X。

  4. 检查microtask队列:

    1. 选择其中最老的任务a,如果任务a不存在,直接结束microtask队列。
    2. 设置任务a为“目前运行的任务”,并执行。
    3. 设置“目前运行的任务”为null,从Microtask队列中移除任务a。
    4. 选择下一个最老的任务b,跳到步骤ii
    5. 直到队列里没有剩余的任务,结束队列。 5.跳回步骤1,检查下一个macrotask任务。

如图:

v2-ad1a251cb91d37625185a4fb874494fc_hd.jpg

上面是一次简单的事件循环的流程图,我们代入下面一段代码进行看看

<script>
var number = 10;
setTimeout(()=>{
   number+=10; // 50+=10
   console.log(number);  //60
})
new Promise((resolve)=>resolve()).then(()=>{
   number = 20;
   console.log(number); // 20
   new Promise(()=>resolve().then()=>{
       number = 50;
       console.log(number), //50
   })
   setTimeout(()=>{
       number+=20; // 60+=20   
       consol.log(number) //80
   })
})
</script>

  1. 用户执行script,整个script其实是一个macrotask,故执行里面的方法 移除(对应上面流程2)
  2. 发现setTimeout,放入下一个macrotask中 移除(对应上面流程2)
  3. 发现Promise.then,放入microtask中移除(对应上面流程2)
  4. 当前运行任务为null,移除(对应上面流程3)
  5. 检查microtask,发现存在promise回调 (对应上面任务4.i
  6. 执行promise回调,发现promise,将其放入microtask,发现setTimeout,将其放入 另外一个macrotask中,这时候还存在2个未执行的macrotask (对应上面4.ii,4.iii
  7. 执行下一个microtask,即number=50对应上面4.iiii
  8. 发现没有microtask了,结束队列 (对应上面4.v
  9. 执行下一个macrotask,即(number+=10;)
  10. 顺序执行,发现不存在microtask,返回第一步(对应上面的2,3,4,5
  11. 执行下一个macrotask,即(number+=20;)
  12. 任务全部执行完成

参考文章

HTML系列:macrotask和microtask

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容