event loop (事件循环/事件轮询)
- JS是单线程运行的
- 异步要基于回调来实现
- event loop 就是异步回调的原理
JS是如何执行的
- 从前到后,一行一行执行
- 有报错,则停止下面的代码运行
- 先把同步代码执行完毕,再执行异步
event loop 的过程
- 同步代码一行一行放在 Call Stack 执行
- 遇到异步,会先记录下,等待时机(定时、网络请求等)
- 时机到了,就移动到 Callback Queue
- 如 Call Stack 为空(即同步代码执行完)event loop 开始工作
- 轮询查找 Callback Queue ,如有则移动到 Call Stack 执行
- 然后继续轮询查找
DOM 事件和 event loop
- JS是单线程的
- 异步(setTimeout、AJAX 等)使用回调,基于 event loop
- DOM 事件也使用回调,基于 event loop
- 特别注意:DOM事件(比如点击事件)不属于异步
Promise
async/await
async/await 是同步语法,彻底消灭回调函数
async/await 和 Promise 的关系
- 执行 async 返回的是 Promise 对象
- await 相当于 Promise 的 then
- try...catch 可捕获异常,代替了 Promise 的 catch
async function fn1(){
return 100
}
const rest1 = fn1()
console.log( 'rest1', rest1 ) //执行 async 函数,返回的是一个 Promise 对象
res1.then(data=>{
console.log('data',data) //100
})
async function fn1(){
const data = await 400 //相当于 await Promise.resolve(400)
console.log(data) //400
}
async function f1(){
console.log(2)
await f2()
console.log(5)
}
async function f2(){
console.log(3)
await 6
console.log(7)
}
console.log(1)
f1()
console.log(4)
//最终输出1,2,3,4,7,5
微任务 microTask 和宏任务 macroTask
什么是宏任务?什么是微任务?
- 宏任务:setTimeout,setInterval,Ajax,DOM事件;宏任务是由浏览器规定的
- 宏任务:DOM 渲染后触发;
- 微任务:Promise,async/await;微任务是 ES6 语法规定的
- 微任务:DOM 渲染前触发
- 微任务执行的时机要比宏任务早
- 微任务和宏任务都是异步任务
conslose.log(100)
setTimeout(()=>{
console.log(200)
})
Promise.resolve().then(()=>{
console.log(300)
})
conslose.log(400)
//最终输出:100,400,300,200
为什么微任务比宏任务渲染的早?
- 每次 Call Stack 清空(即每次轮询结束),即同步任务执行完
- 都是 DOM 重新渲染的机会,DOM 结构如有改变则重新渲染
- 然后再去触发下一次 Event Loop
async/await面试题
async function async1 (){
console.log('async1 start')
await async2()
console.log('async1 end')
}
async function async2 (){
console.log('async2')
}
console.log('script start')
setTimeout(function(){
console.log('setTimeout')
},0)
async1()
//初始化 Promise 的时候,Promise 里面传入的函数会立即执行
new Promise(function(resolve){
console.log('promise1')
resolve()
}).then(function(){
console.log('promise2')
})
console.log('script end')
答案如图:
for....of (用于异步循环)