关于javascript:一起谈一谈js中的宏任务和微任务

40次阅读

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

后面面试的文章中咱们说过一道对于宏工作和微工作的题:

setTimeout(function(){console.log('1')
});
 
new Promise(function(resolve){console.log('2');
     resolve();}).then(function(){console.log('3')
});
 
console.log('4')

试问一下下面代码的执行程序是啥?

有小伙伴可能会答:2,4,1,3

估摸着是这么想的:我难道不晓得 js 是一行一行执行的,setTimeout 是异步,所以先放前面;往下走,执行了 console.log(2),.then()是异步的,放在前面;走了 console.log(4); 再去异步队列里走,先是 console.log(1); 再是 console.log(3)。

But,事实真是如此吗?我有点慌,于是我粘贴到浏览器去瞅两眼:

 我擦嘞,竟然是2,4,3,1!我几乎不敢相信!

带着困惑的我,只能去好好钻研钻研 JavaScript 的运行机制了!

1、对于 JavaScript

JavaScript 是一门单线程语言,即一次只能实现一个工作,若有多个工作要执行,则必须排队依照队列来执行(前一个工作实现, 再执行下一个工作)。

2、JavaScript 事件循环

既然 js 是 单线程,那就像只有一个窗口的食堂,学生须要排队一个一个打饭,同理 js 工作也要一个一个程序执行。这种模式执行简略,但随着日后的需要,事务,申请增多,这种单线程模式执行效率必然低下。只有有一个工作执行耗费了很长时间,在这个工夫里前面的工作无奈执行。

常见的有新闻蕴含的超清图片加载很慢,难道咱们的网页要始终卡着直到图片齐全显示进去?为了解决这个问题,JavaScript 语言将工作执行模式分成同步和异步:

同步模式: 就是下面所说的一种执行模式,后一个工作期待前一个工作完结,而后再执行,程序的执行程序与工作的排列程序是统一的、同步的。

异步模式: 就是每一个工作有一个或多个回调函数(callback),前一个工作完结后,不是执行后一个工作,而是执行回调函数,后一个工作则是不等前一个工作完结就执行,所以程序的执行程序与工作的排列程序是不统一的、异步的。

导图要表白的内容用文字来表述的话:

  • 同步和异步工作别离进入不同的执行 ” 场合 ”,同步的进入主线程,异步的进入 Event Table 并注册函数。
  • 当指定的事件实现时,Event Table 会将这个函数移入 Event Queue。
  • 主线程内的工作执行结束为空,会去 Event Queue 读取对应的函数,进入主线程执行。
  • 上述过程会一直反复,也就是常说的 Event Loop(事件循环)。

 再配上代码表白:

let data = [];
$.ajax({
    url:blog.csdn.net,
    data:data,
    success:() => {console.log('发送胜利!');
    }
})
console.log('代码执行完结');

下面是一段繁难的 ajax 申请代码:

  • ajax 进入 Event Table,注册回调函数success
  • 执行console.log('代码执行完结')
  • ajax 事件实现,回调函数 success 进入 Event Queue。
  • 主线程从 Event Queue 读取回调函数 success 并执行。

置信通过下面的文字和代码,你曾经对 js 的执行程序有了初步理解。然而这也是为什么会有小伙伴答复 2,4,1,3 的起因。

然而实际上,异步队列里是还有门道的,咱们那道面试题,setTimeout 和 promise 的.then()都在异步队列了!接下来,讲讲那些门道 ( 宏工作和微工作)。

3、宏工作和微工作

每个人的了解形式不同,因为宏工作和微工作并不是规范,但执行的程序在 js 中是大一统了的。

宏工作

# 浏览器 Node
<script> 整体代码
setTimeout
setInterval
setImmediate x
requestAnimationFrame x
Ajax
DOM 事件

微工作

# 浏览器 Node
process.nextTick x
MutationObserver x
Promise.then catch finally

宏工作包含:<script> 整体代码、setTimeout、setInterval、setImmediate、Ajax、DOM 事件 \
微工作:process.nextTick、MutationObserver、Promise.then catch finally

process.nextTick 差别太大,不同的 node 执行不对立,不做规范 \
微工作比宏工作的执行工夫要早

Tip: 有些人喜爱将 <script> 整体代码放在宏工作里,但我集体不喜爱,在我这里它只是第一执行的主线程,我集体是将宏工作和微工作都归类到异步工作里!

咱们再来看看那道面试题:

// 回调才是异步工作
setTimeout(function(){// 宏工作
     console.log('1')
});
 
new Promise(function(resolve){console.log('2');// 同步主线程
     resolve();}).then(function(){// 微工作
    console.log('3')
});
 
console.log('4')// 同步主线程

2:同步中的第一个,故第一

4:同步中的第二个,故第二

3:异步中的微工作,故第三

1:异步中的宏工作,故第二

因而:2,4,3,1 的后果就进去了!

除此咱们来拓展一下:

setTimeout(() => {// 宏工作队列 1
  console.log('1');// 宏工作队 1 的工作 1

  setTimeout(() => {// 宏工作队列 3(宏工作队列 1 中的宏工作)
    console.log('2')
  }, 0)

  new Promise(resolve => {resolve()
    console.log('3')// 宏工作队列 1 的工作 2
  }).then(() => {// 宏工作队列 1 中的微工作
    console.log('4')
  })

}, 0)
 
setTimeout(() => {// 宏工作队列 2
  console.log('5')
}, 0)

console.log('6')// 同步主线程

执行整体代码(宏工作)console.log(‘6’) >> 宏工作队列 1、宏工作队列 2 位异步(顺次执行)

宏工作队列 1:=>

        console.log(‘1’)

        console.log(‘3’)

        console.log(‘4’)// 宏工作中的微工作

        剩下的不会先执行,因为是宏工作中的宏工作(console.log(2)),要被持续丢进工作队列后   

宏工作队列 2:=>

         console.log(‘5’)

宏工作队列 1 中的宏工作 3:=>

        console.log(‘2’)

 以上代码会怎么输入呢?

4、拓展宏工作微工作

下面出了简单的题,小伙伴们无妨能够想一想,这种简单状况,一个套一个的该怎么执行呢?

整体代码:

  • 6:第一个同步主线程,故第一

script 整体代码里没有微工作故间接执行宏工作 =>

宏工作队列:

  • 宏工作队列 1

        工作 1:console.log(1)

        工作 2:console.log(3)

        宏工作队列 1 中的微工作:console.log(4)

        宏工作队列 3:因他是宏工作队列 1 中的宏工作,所以被丢进了工作队列最初,咱们先看宏工作队列 1 同级的是否还有宏工作,有就先执行同级的,没有才能够执行宏工作队列 3!故 最初

  • 宏工作队列 2  

        console.log(5)

所以输入的后果是什么?是6,1,3,4,5,2

通过验证,后果正确!


5、总结

实际上你只须要晓得拓展之前的,毕竟拓展后的的确比较复杂,须要肯定的理解能力,他能够三层,能够四层等 …. 我不信你会跟这题目一样写代码,这不是憨批是什么😆。

对于宏工作和微工作请记住这几点:

  • 微工作比宏工作执行要早。
  • 宏工作里如果有宏工作,不会执行外面的那个宏工作,而是被丢进工作队列前面,所以会最初执行。

此上就是我给大家的分享,如果有用,还望各位来个三连反对一下哟~~~感激🙏 各位了。

最初出个题:

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')
    })
})

这题里有 process.nextTick,请在 nodejs 中验证哦~

正文完
 0