JavaScript的事件分两种,宏任务(macro-task)和微任务(micro-task)
先记住两个概念:
宿主环境提供的叫宏任务,由语言标准提供的叫微任务,这是算比较标准也算比较好记忆的区分宏任务和微任务了。
宿主环境:
简单来说就是能使javascript完美运行的环境,只要能完美运行javascript的载体就是javascript的宿主环境。目前我们常见的两种宿主环境有浏览器和node。宿主环境内所有的内建或自定义的变量/函数都是 global/window 这个全局对象的属性/方法,而由宿主环境提供的也叫宏任务。
语言标准:
我们都知道JavaScript是一种编程语言,但其实JavaScript由ECMA制定标准,称之为ECMAScript,所以由语言标准提供的就是微任务,比如ES6提供的promise.then()方法。
- 宏任务:包括整体代码script,setTimeout,setInterval
- 微任务:Promise.then(非new Promise),process.nextTick(node中)
- 事件的执行顺序,是先执行宏任务,然后执行微任务,这个是基础,任务可以有同步任务和异步任务,同步的进入主线程,异步的进入Event Table并注册函数,异步事件完成后,会将回调函数放入Event Queue中(宏任务和微任务是不同的Event Queue),同步任务执行完成后,会从Event Queue中读取事件放入主线程执行,回调函数中可能还会包含不同的任务,因此会循环执行上述操作。

执行一个宏任务(先执行同步代码)-->执行所有微任务-->UI render-->执行下一个宏任务-->执行所有微任务-->UI render-->......
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')
})
})
输出:
1
2
4
3
5
- 宏任务同步代码console.log('1')
- setTimeout,加入宏任务Event Queue,没有发现微任务,第一轮事件循环走完
- 第二轮事件循环开始,先执行宏任务,从宏任务Event Queue中独取出setTimeout的回调函数
- 同步代码console.log('2'),发现process.nextTick,加入微任务Event Queue
- new Promise,同步执行console.log('4'),发现then,加入微任务Event Queue
- 宏任务执行完毕,接下来执行微任务,先执行process.nextTick,然后执行Promise.then
- 微任务执行完毕,第二轮事件循环走完,没有发现宏任务,事件循环结束
/**
* 1. 程序先执行同步任务,在执行异步任务
* 2.同步任务分为宏任务和微任务
*/
async function testSometing() {
console.log("执行testSometing");
return "testSometing";
}
async function testAsync() {
console.log("执行testAsync");
return Promise.resolve("hello async");
}
async function test() {
console.log("test start...");
new Promise(resolve => {
console.log("async 里面的promise");
resolve("async里面的promise里面的then");
}).then(data => {
console.log(data);
});
const v1 = await testSometing();
console.log(v1);
const v2 = await testAsync();
console.log(v2);
console.log(v1, v2);
}
test();
var promise = new Promise(resolve => {
console.log("promise start..");
resolve("promise");
}); //3
promise.then(val => console.log(val));
setTimeout(() => {
console.log("setTime1");
}, 3000);
console.log("test end...");
/*
>
执行test函数,输出'test start...' 'async 里面的promise'
testSometing函数执行类似 new Promise(resolve => {})里面的宏任务 await类似then回调执行,属于testSometing队列中的微任务 输出'执行testSometing'
输出'promise start..'
输出'test end...'
执行微任务
输出'async里面的promise里面的then' 'testSometing' '执行testAsync' 'promise'
输出'hello async' 'testSometing hello async'
三秒后输出 'setTime1'
1. 程序从上到下执行,遇到test()函数执行,执行test函数里面的代码,同样分为同步异步的情况
1)输出 “test start...”
2)Promise是一个宏任务 输出 “async 里面的promise” 后续代码会被推入微任务队列
3)遇见 await await后面的会被转换为Promise Promise里面的代码是宏任务,then()里面的代码是微任务,所以执行后面的 testSometing 这个函数,需要分析 testSomething 这个函数 输出“执行testSometing” 遇到函数的返回值,对应 await 来说,这个return的值作为 then 里面的参数,会被 v1这个变量接收 await 会阻止后续代码的执行 test() 目前执行完毕
4)遇见 promise 输出 ‘promise start..’ 后续代码推入到微任务
5)后续遇见定时器,异步任务,推入异步队列
6)输出 “test end” 全部宏任务执行完毕,检查微任务队列
7)第一个微任务是执行 test()函数推入的 输出“async里面的promise里面的then”
8)还记得 test() 里面的await 后面的 微任务执行 输出 “test something”
9) 继续向下执行 执行 testAsync 输出 "执行testAsync"
10) 再次推入微任务
11)执行 promise 那一个微任务 输出 promise
12)10步的时候推入了一个微任务,继续执行 输出 “hello async”
13)遇见 console 执行 “testSometing hello async”
14)微任务执行完毕 执行异步任务,就是定时器 输出 “setTime1”
*/
网友评论