# Promise
# 状态
1 2 3 4 5 6 7 8 9
| const promise = new Promise((resolve, reject) => { console.log(1); console.log(2); }); promise.then(() => { console.log(3); }); console.log(4);
|
Promise 只有三种状态,Pending、Resolve、Reject,上面代码一直处于 Pending,所以 then 不会被执行,
new Promise 中的代码也算是同步代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const promise1 = new Promise((resolve, reject) => { console.log('promise1') resolve('resolve1') }) const promise2 = promise1.then(res => { console.log(res) }) console.log('1', promise1); console.log('2', promise2);
|
按顺序执行,输出 1 时 promise1 已经变为 resolve 状态,输出 2 时 promise2 还是 pending (因为 then 中未 return,如果 return 则将返回一个新的 promise 包装 return 值且 promise 状态为 resolve)
执行完同步代码后执行微任务 then (即便 then 中 return 也无法改变上面结果,因为 promise2 的状态改变是在同步代码执行完后的下一个微任务中)
1 2 3 4 5 6 7 8 9 10 11 12
| const promise = new Promise((resolve, reject) => { resolve('success1'); reject('error'); resolve('success2'); }); promise.then((res) => { console.log('then:', res); }).catch((err) => { console.log('catch:', err); })
|
# 链式调用
1 2 3 4 5 6 7 8 9 10 11
| Promise.resolve(1) .then(2) .then(Promise.resolve(3)) .then(console.log)
Promise.resolve(1) .then(2) .then(() => Promise.resolve(3)) .then(console.log)
|
then 方法接受的参数是函数,而如果传递的并非是一个函数,它实际上会将其解释为 then (null),这就会导致前一个 Promise 的结果会传递下面。
Promise.resolve (3) 是一个对象
1 2 3 4 5 6 7 8 9 10 11 12 13
| Promise.resolve().then(() => { return new Error('error!!!') }).then(res => { console.log("then: ", res) return 1 }).catch(err => { console.log("catch: ", err) }).then(res => { console.log(res) })
|
容易搞错的地方在于这里是 return 而非 throw
then 之后会穿透 catch 执行下一个 then
1 2 3 4 5
| const promise = Promise.resolve().then(() => { return promise; }) promise.catch(console.err)
|
1 2 3 4 5 6 7 8 9
| Promise.reject('err!!!') .then((res) => { console.log('success', res) }, (err) => { console.log('error', err) }).catch(err => { console.log('catch', err) })
|
这里直接被 then 的第二个参数拦截捕获了,也就不会执行 catch(then 函数中的两个参数:第一个参数是用来处理 Promise 成功的函数,第二个则是处理失败的函数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| Promise.resolve('1') .then(res => { console.log(res) }) .finally(() => { console.log('finally') }) Promise.resolve('2') .finally(() => { console.log('finally2') return '我是finally2返回的值' }) .then(res => { console.log('finally2后面的then函数', res) })
Promise.resolve('1') .finally(() => { console.log('finally1') throw new Error('我是finally中抛出的异常') }) .then(res => { console.log('finally后面的then函数', res) }) .catch(err => { console.log('捕获错误', err) })
|
finally 不接受任何参数,默认会把上一个 promise 状态的值 return 传递下去,且不可通过人为 return 改变,只能通过 throw 改变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| function runAsync (x) { const p = new Promise(r => setTimeout(() => r(x, console.log(x)), 1000)) return p } function runReject (x) { const p = new Promise((res, rej) => setTimeout(() => rej(`Error: ${x}`, console.log(x)), 1000 * x)) return p } Promise.all([runAsync(1), runReject(4), runAsync(3), runReject(2)]) .then(res => console.log(res)) .catch(err => console.log(err))
|
这里主要注意:
catch 只触发一次
且 Promise.all 抛出 reject 时,runReject (4) 函数仍然在执行
另外如果在 then 函数中添加第二个参数,则会拦截执行使后面的 catch 不会执行,且只执行一次,因为 promise 状态改变已触发链式调用,后续 Promise.all 的结果并不会再次触发链式调用 (race 方法或 any 方法也是)
# async/await
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); } async function async2() { console.log("async2"); } async1(); console.log('start')
|
这里可以理解为 await 后面的语句相当于放到了 new Promise 中(不同点在于这个 promise 会在运行完代码后自动 resolve 或 reject,除非 async2 手动 new Promise),下一行及之后的语句相当于放在 Promise.then 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| async function async1() { console.log("async1 start"); await async2(); console.log("async1 end"); setTimeout(() => { console.log('timer1') }, 0) } async function async2() { setTimeout(() => { console.log('timer2') }, 0) console.log("async2"); } async1(); setTimeout(() => { console.log('timer3') }, 0) console.log("start")
|
宏任务微任务练习题,then 是微任务,定时器是宏任务,执行顺序为同步代码 -> 微任务 -> 宏任务,且注意定时器运行顺序即为添加顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| async function async1 () { console.log('async1 start'); await new Promise(resolve => { console.log('promise1') }) console.log('async1 success'); return 'async1 end' } console.log('srcipt start') async1().then(res => console.log(res)) console.log('srcipt end')
|
上面说过 await 可以当作 new Promise,而 await 后面的代码则可以当作 then,该代码中 promise 以及 async1 的状态一直是 pending,所以 await 后面代码以及下面的 then 不会执行
promise 的状态改变需要 resolve 触发,async1 需要 return 触发
# 宏任务和微任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| console.log(1)
setTimeout(() => { console.log(2) })
new Promise(resolve => { console.log(3) resolve(4) }).then(d => console.log(d))
setTimeout(() => { console.log(5) new Promise(resolve => { resolve(6) }).then(d => console.log(d)) })
setTimeout(() => { console.log(7) })
console.log(8)
|
浏览器的 EventLoop 会在执行下一个宏任务之前清空当前的微任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| 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') }) })
|