JavaScript 事件循环(宏任务微任务)

JavaScript 事件循环 宏任务微任务

JavaScript 的执行机制

  • js 是单线程的,js 任务需要一个一个执行,如果某一个任务过长,那么后面的任务就必须等着,但当我们打开一个网页时,有很多超级清楚的图片,那不就卡着一直显示不出来吗,因为可以将任务分为两类:
  • 异步任务
  • 同步任务

什么是时间循环

  1. 让同步任务和异步任务分别进入不同的执行”场所“,同步的进入主线程,异步的进入 Event table 并注册函数。
  2. 当指定的事情完成时,Event table 会将整个函数移入 Event Queue (队列)
  3. 主线程内的任务执行完毕为空后,会去 Event Queue 读取对应的函数,进行主线程执行。
  4. 上面的过程不断的重复,也就是我们常说的 Event Loop 事件循环。

怎么知道主线程执行栈为空?

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

ajax

let data = [];
$.ajax({
  url:www.javascript.com,
  data:data,
  success:() => {
    console.log('发送成功!');
  }
})
console.log('代码执行结束');
  • ajax 进入 Event table,注册回调函数 success
  • 执行 console
  • ajax 事件完成,回调函数 success 进入 Event Queue
  • 主线程从 Event Queue 读取回调函数 success 执行。

setTimeout

  • 定时器
setTimeout(() => {
  console.log('123')
}, 1000)
console.log('console')
  • 延迟一秒执行
    但是有些时候,当前一个任务还没执行完,而 设置的延迟时间已经到了,并没有执行。
    setTimeout(fn, 0) 这样并不会在 0 毫秒之后执行,主线程任务空闲时,不用再等多少秒执行,但写 0 没有意义,根据不同的浏览器,默认的时间是不一样的。

  • Promise 与 process.nextTick(callback)
    process.nextTick(callback)类似node.js版的"setTimeout",在事件循环的下一次循环中调用 callback 回调函数。

  • macro-task 宏任务: 包括整体代码 script, setTimeout, setInterval

  • micro-task 微任务: promise,process.nextTick

事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

setTimeout(function() {
  console.log('setTimeout');
})

new Promise(function(resolve) {
  console.log('promise');
}).then(function() {
  console.log('then');
})

console.log('console');
  • 这个代码作为宏任务,进入主线程
    先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
    接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue。
    遇到console.log(),立即执行。
    好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
    ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。
    结束。
console.log('1');

setTimeout(function() {
  console.log('2');
  process.nextTick(function() {
    console.log('3');
  })
  new Promise(function(resolve) {
    console.log('4');
    resolve();
  }).then(function() {
    console.log('5')
  })
})
process.nextTick(function() {
  console.log('6');
})
new Promise(function(resolve) {
  console.log('7');
  resolve();
}).then(function() {
  console.log('8')
})

setTimeout(function() {
  console.log('9');
  process.nextTick(function() {
    console.log('10');
  })
  new Promise(function(resolve) {
    console.log('11');
    resolve();
  }).then(function() {
    console.log('12')
  })
})

  1. 代码作为第一个宏任务进入主线程,执行 console
  2. 遇到 setTimeout 把他的回调函数分发到宏任务 Event Queue 为 setTimeout1
  3. process.nextTick,函数分发到 Event Queue 中,记录 process1
  4. Promise 直接执行,输出7,then 被分发到微任务中,记录为 then1
  5. 又遇到 setTimeout,把他的回调函数分发到宏任务 Event Queue 为 setTimeout2

此时,已经有 宏任务 setTimeout1, setTimeout2, 微任务 process1 then1

  1. 发现有两个微任务,执行这两个微任务 process1 then1

此时,第一轮事件循环结束

  1. 第二轮从 setTimeout1 宏任务开始:输出 console,将 rocess.nextTick(),同样将其分发到微任务Event Queue中,记为process2。new Promise立即执行输出4,then也分发到微任务Event Queue中,记为then2。

此时有 宏任务 setTimeout2,和 微任务 process2 then2 未执行。

  1. 执行这两个微任务 process2 then2

此时 ,第二轮结束

  1. 第三轮开始,执行宏任务 setTimeout2 ,它有两个微任务 将process.nextTick()分发到微任务Event Queue中。记为process3。将then分发到微任务Event Queue中,记为then3。
  2. 执行这两个微任务,结束。

浏览器和Node事件循环的区别

  • 微任务和宏任务在Node的执行顺序

  • Node 10以前:
    执行完一个阶段的所有任务
    执行完nextTick队列里面的内容
    然后执行完微任务队列的内容

  • Node 11以后:
    和浏览器的行为统一了,都是每执行一个宏任务就执行完微任务队列。

  • js的异步
    我们从最开头就说javascript是一门单线程语言,不管是什么新框架新语法糖实现的所谓异步,其实都是用同步的方法去模拟的,牢牢把握住单线程这点非常重要。

  • 点击查看更多内容

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