同步任务
同步任务都在主线程上执行,形成一个执行栈,程序执行的时候,按照顺序依次执行
异步任务
异步任务是通过回调函数实现的,程序执行的时候,程序会调过某个步骤继续向下执行
事件循环
描述了计算机在执行js时候的一个状态(先去执行栈中执行同步代码,然后再执行队列中异步代码)
异步任务相关添加到任务队列中(任务队列也成为消息队列)
异步任务分类
异步任务分为宏任务和微任务两种:
微任务处理完毕后才会处理宏任务,而该异步任务被判定为宏还是微取决于官方的定义。常见分类如下:
-
宏任务:正常的异步任务都是宏任务,最常见的就是定时器(setInterval, setImmediate, setTimeout);script(整体代码) 、用户交互、IO任务;
-
微任务:微任务出现比较晚,queueMicrotask、Promise的then和catch方法、catch、finally
微任务生成方法:
Promise:Promise是一种异步编程的解决方案,它可以将异步操作封装成一个Promise对象,通过then方法注册回调函数,当promise变为resolve或者reject会将回调函数加入微任务队列中。 MutationObserver:MutationObserver是一种可以观察DOM变化的API,通过监听DOM变化事件并注册回调函数,将回调函数加入微任务队列中。 process.nextTick:process.nextTick是Node.js中的一个API,它可以将一个回调函数加入微任务队列中。
宏任务生成方法:
用户交互:用户在页面上进行交互操作(例如点击、滚动、输入等),会触发浏览器产生宏任务来响应用户操作。 网络请求:当浏览器发起网络请求(例如通过 Ajax、Fetch、WebSocket 等方式)时,会产生宏任务来处理请求和响应。 定时器:通过 JavaScript 宿主环境提供的定时器函数(例如 setTimeout、setInterval)可以设置一定的时间后产生宏任务执行对应的回调函数。 DOM 变化:当 DOM 元素发生变化时(例如节点的添加、删除、属性的修改等),会产生宏任务来更新页面。 跨窗口通信:在浏览器中,跨窗口通信(例如通过 postMessage 实现)会产生宏任务来处理通信消息。 JavaScript 脚本执行事件;比如页面引入的 script 就是一个宏任务。
执行顺序代码演示
setTimeout(function(){
console.log(777)
},10)
console.log('000');//第一步
(async ()=>{
console.log(111);//2
await console.log(222);//3,此行执行,当await右边跟随的代码执行完毕的时候,才会执行后面的代码,此时后面的代码(后面3行)也可以算作“内部的微任务”,所以此行执行后执行输出333
await fn()
console.log(444);
console.log(555);
})().then(()=>{
console.log(666);
});
function fn(){
console.log('a')
return new Promise((res,rej)=>{
console.log('b')
res('d')
console.log('c')
})
}
console.log('333');//4
输出:
注意:
promise内部遇到resolve()和reject()调用的时候,会继续执行后面的代码,但是then和reject就直接放入为微任务队列中,等待同步任务执行
但async内部遇到await的时候,只有当await右边跟随的代码执行完毕的时候,才会执行后面的代码,此时后面的代码也可以算作内部的微任务(因为遇到await会将等await执行完成后,执行外面的同步任务,再执行await后面的任务,见下图)
setTimeout(function(){
console.log(777)
},10)
console.log('000');//第一步
(async ()=>{
console.log(111);//2
await console.log(222); //3,此行执行,当await右边跟随的代码执行完毕的时候,才会执行后面的代码,此时后面的代码(237-239行)也可以算作内部的微任务,所以此行执行后执行252行
await fn()
console.log(444);
console.log(555);
})().then(()=>{
console.log(666);
});
async function fn(a){
console.log(a+'a')
await console.log(222222)
return new Promise((res,rej)=>{
console.log(a+'b')
res(a+'d')
console.log(a+'c')
})
}
fn(1).then((e)=>{
console.log(e);
})
console.log('333');