JavaScript是单线程的语言,也就是说同一时间只能进行一个任务,毕竟JavaScript可以操作dom,进行ui交互,删除dom和修改dom同时进行,那么应该听哪一个?。

正是因为这样,决定了它是单线程的,但是又说单线程只能在同一个时间内执行一个任务,这样岂不是会造成阻塞?前一个任务执行很久,后面都卡死了,所以就需要JavaScript的事件循环机制来进行分配,这样就会被分为

宏任务:当前调用栈执行的代码称为宏任务

宏任务有哪些?

微任务:当前宏任务执行完,在下一个宏任务开始之前需要执行的在队列(先进先出)里的任务,可理解为回调事件

微任务有哪些?

运行机制,面试中经常会遇到这样的题目(让说出它的执行顺序):

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

执行结果:1 5 3 4 2

先了解一下运行机制:

1. 在执行栈中执行一个宏任务(程序刚开始执行时,会把整个代码当成第一个宏任务)。

2. 执行的过程中遇到微任务,先将微任务添加到微任务队列中(它是属于本次执行的宏任务中分出来微任务),遇到宏任务,放到下一个执行栈中。

3. 当前宏任务执行完毕,立即执行任务队列(先进先出的原则)中的微任务

4. 当前微任务队列中的任务执行完毕

5. 接着开始执行执行栈中的下一个宏任务,

6. 依次循环这个规律

解析上面的代码:

1. 整体代码被当成第一个宏任务,代码从上到下执行

2. 遇到console.log('1');是同步任务,直接执行,输出1

3. 遇到setTimeout,是宏任务,放到执行栈中

4. 再往下执行,遇到promise,promise的执行器里是立即执行的,这里没有执行器,而是有then,then是微任务,先放到本次宏任务的微任务队列中,then后面返回的也是一个promise,第二个then也是一个微任务,放到微任务队列中。

5.接着遇到同步代码console.log('5');直接输出5,这时候,第一轮宏任务执行完毕

6.需要去执行本轮它产生的微任务,先进先出的原则,输出3 4

7.这时候循环的第一周期就结束了

8.再去执行栈中的第二个宏任务,输出 2


来个难的练习一下:

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 7 6 8 2 4 3 5 9 11 10 12

process.nextTick 需要放在node环境下才能执行:

javascript获取宏任务队列(JavaScript的宏任务和微任务)(1)


加上async和await

async function async1() { console.log('1'); let a = await async2(); console.log(a); console.log('2'); } async function async2() { return new Promise((resolve) => { setTimeout(() => { resolve('data'); }, 0); }); } console.log('3'); setTimeout(function () { console.log('4'); }, 0); async1(); new Promise(function (resolve) { console.log('5'); resolve(); }).then(function () { console.log('6'); }); console.log('7'); // 3 1 5 7 6 4 data 2

提示:

  1. await是一个让出线程的标志
  2. 正常情况下, await 命令后面是一个 Promise 对象。如果不是,会被转成一个立即 resolve 的 Promise 对象
  3. 当函数执行的时候, 一旦遇到 await 就会先返回,跳出函数体执行外部的代码,等到异步操作完成,再接着执行函数体内后面的代码。
,