Promise
promise 三种状态
1.pending、resolved(fulfilled)、 rejected
2.pending --> resolved(fulfilled) 或者 pending --> rejected
3.变化不可逆
状态的表现
1.pending 状态,不会触发 then 和 catch
2.resolved(fulfilled) 状态,会触发后续的 then 回调函数
3.rejected 状态,会触发后续的 catch 回调函数
then 和 catch 改变状态
1.then 正常返回 resolved(fulfilled),里面有报错则返回 rejected(指抛出错误)
2.catch 正常返回 resolved(fulfilled),里面有报错则返回rejected(指抛出错误)
Promise.resolve().then(() => {
console.log(1); // 1
// 执行完 then 回调函数没有报错,正常返回 resolved(fulfilled)
}).catch(() => {
console.log(2);
}).then(() => {
console.log(3); // 3
// 执行完 then 回调函数没有报错,正常返回 resolved(fulfilled)
})
Promise.resolve().then(() => {
console.log(1); // 1
// 有报错则返回 rejected 状态
throw new Error('erro1')
}).catch(() => {
console.log(2); // 2
// 执行完 catch 回调函数没有报错,正常返回 resolved(fulfilled)
}).then(() => {
console.log(3); // 3
// 执行完 then 回调函数没有报错,正常返回 resolved(fulfilled)
})
Promise.resolve().then(() => {
console.log(1); // 1
// 有报错则返回 rejected 状态
throw new Error('erro1')
}).catch(() => {
console.log(2); // 2
// 执行完 catch 回调函数没有报错,正常返回 resolved(fulfilled)
}).catch(() => {
console.log(3);
})
async/await
- 异步回调容易导致 callback hell
- Promise then catch 链式调用虽把层级铺开,但也是基于回调函数
- async/await 是同步语法,彻底消灭回调函数
async/await 和 Promise 的关系
- 执行 async 函数,返回的是 Promise 对象
- await 相当于 Promise 的 then,await 的后面都可以看做是 callback 里的内容,即异步
- try…catch 可捕获异常,代替了 Promise 的 catch
async function fn2(){
retrun 200
}
const res1 = fn2() // 执行 async 函数,返回的是一个 Promise 对象
console.log('res1', res1); // Promise 对象
res1.then( data =>{
console.log('data', data); // 200
})
(async function(){
const p1 = Promise.resolve(300)
const data = await p1 // await 相当于 Promise.then
console.log('data', data) // 300
})()
(async function(){
const data1 = await 400 // await Promise.resolve(400)
console.log('data1', data1); // 400
})()
(async function(){
const data2 = await fn2()
console.log('data2', data2 ); // 200
})()
(async function(){
const p3 = Promise.reject('err3') // rejected 状态
// 此时因为 await 相当于 Promise.then,而 p3 为 reject 状态,故这里会报错
const res = await p3
console.log(res);
})()
// try...catch 相当于 Promise catch
(async function(){
const p4 = Promise.reject('err4') // rejected 状态
try {
// 此时因为 await 相当于 Promise.then,而 p4 为 reject 状态,故这里会报错,进入 catch
const res = await p4
console.log(res);
} catch (error) {
console.log(error); // err4
}
})()
微任务(microTask)和宏任务(macroTask)
- 微任务:Promise.then/catch、mutationObserver
- 宏任务:setTimeout、setInterval、整体代码script、I/O、UI render、ajax
- 微任务执行时机比宏任务要早
event loop
JavaScript 设计者在广义上将所有任务分成两种:同步任务(synchronous)、异步任务(asynchronous),运行机制如下:
- 所有同步任务都在主线程上执行,形成一个 执行栈;
- 主线程外,还存在一个 任务队列,只要异步任务有了运行结果,就在任务队列中放置一个事件;
- 一旦执行栈中所有同步任务执行完毕,系统就会取出任务队列中事件对应的回调函数进入执行栈,开始执行;
- 主线程不断重复上面的第三步。
将任务更精细的定义分为 宏任务 和 微任务,运行机制如下:
- 首先将执行栈最开始的所有同步代码(宏任务)执行完成;
- 检查是否有微任务,如有则执行所有微任务;
- 取出任务队列中事件对应的回调函数(宏任务)进入执行栈并执行完成;
- 再检查是否有微任务,如有则执行所有的微任务;
- 主线程不断重复上面的 3、4 步。
event loop 和 DOM 渲染
- 每次 Call Stack(调用栈)清空(即每次轮询结束),即同步任务执行完
- 都是 DOM 重新渲染的机会,DOM 结构如有改变则重新渲染
- 然后再去触发下一次 Event Loop
微任务、宏任务 和 DOM 渲染的关系
- 微任务在 DOM 渲染前触发
- 宏任务在 DOM 渲染后触发
微任务和宏任务的根本区别
- 微任务是 ES6 语法规定的
- 宏任务是 W3C规范浏览器规定的