本篇粗略地进行阅读总结,还有许多遗漏的地方后续慢慢补上~
promise连锁与合成
promise连锁
-
因为每个promise实例的方法 then catch finally 都会返回一个新的promise对象,可以链式调用
-
要执行异步任务,可以让每个执行器都返回一个promise实例,让后续promise都等待之前的promise,也就是串行化异步任务
每个后续的处理程序都会等待前一个promise解决,然后实例化一个新promise并返回它,这种结构可以简洁地将异步任务串行化,解决之前回调的问题
function delayedResolve(str) { return new Promise((resolve, reject) => { console.log(str); setTimeout(resolve, 1000) }) } delayedResolve('1') // 1s后:1 .then(() => delayedResolve('2')) // 2s后:2 .then(() => delayedResolve('3')) // 3s后:3
Promise.all()
const p = Promise.all([p1, p2, p3]);
-
用于将多个Promise实例包装成一个新的Promise实例
-
参数
接受一个数组作为参数 也可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
-
p的状态
只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数 只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数,但是并不影响所有promise的拒绝操作,不会有错误跑掉
-
注意
如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法
let p = Promise.all([
Promise.resolve(1),
Promise.resolve(),
Promise.resolve(2)
])
p.then(value => console.log(value)) [1, undefined, 2]
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
// p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved
// 导致Promise.all()方法参数里面的两个实例都会resolved 因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// Error: 报错了
// 如果p2没有自己的catch方法,就会调用Promise.all()的catch方法
race()
-
也是用于将多个 Promise 实例,包装成一个新的 Promise 实例
-
与 all()的区别
-
不需要等所有实例的状态发生变化 只要有一个状态发生变化 就会把这个实例的返回值传给 race的Promise实例
-
如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve
-
如果有一个promise拒绝,只要它是第一个转变状态的,就会成为拒绝合约Promise的理由。之后再拒绝的promise不会影响最终promise的拒绝理由。!这并不影响所有报刊promise正常的拒绝操作。合成的promise会静默处理所有包含promise的拒绝操作,即 不会有错误跑掉,不会有未处理的错误
let p = Promise.race([ Promise.reject(3), new Promise((resolve, reject) => setTimeout(reject, 1000)) ]) p.catch((reason) => console.log(reason)) // 立即输出 3 // !!! 虽然只有第一个promise的拒绝理由会进入拒绝处理程序,但是第二个promise的拒绝也会被静默处理,不会有错误跑掉 -
-
实例
使用场景 请求超时提醒 如信号不好时发出给提醒
function request() {
return new Promise((resolve,reject)=>{
setTimeout(()=>{
resolve('请求成功')
},4000)
})
}
function timeout() {
return new Promise((resolve,reject)=>{
setTimeout(()=>{
reject('信号不佳,请求超时')
},3000)
})
}
Promise.race([request(),timeout()]).then((value)=>{
console.log(value);
}).catch((reason)=>{
console.log(reason);
}) // 信号不佳,请求超时
异步函数
也称为 async/await(语法关键字),是ES8规范新增的,让同步方式写的代码可以异步执行
async
- 该关键字用于声明异步函数,可以用在
函数声明、函数表达式、箭头函数和方法上
async function foo() { }
let bar = async function () { };
let baz = async () => { };
class Qux {
async qux() { }
}
- 异步函数如果使用
return返回了值(没有返回undefined),这个值会被Promise.resolve()包装成一个promise对象,异步函数始终返回promise对象,在函数外部调用这个函数可以得到它返回的promise
async function foo() {
console.log(1);
return 3 // 等同于 return Promise.resolve(3)
}
console.log(foo()); // Promise {<fulfilled>: 3}
await
- 异步函数主要针对不会马上完成的任务,使用await关键字可以暂停异步函数代码的执行,等待promise解决
- 该关键字会暂停执行函数后面的代码,让出js运行时的执行线程,这个行为和生成器函数中的
yield关键字是一样的 - 可以单独使用,也可以在表达式中使用
- 单独的Promise.reject()不会被异步函数捕获,而会抛出未捕获错误。不过,对拒绝的promise使用await则会释放错误值(将拒绝promise返回)
async function foo() {
await new Promise((resolve, reject) => setTimeout(resolve, 2000))
console.log(111);
}
foo() // 2s后打印111
// 观察以下输出有什么区别
async function foo() {
console.log(1);
await Promise.reject(2)
console.log(3); // 这行代码不会执行
}
foo().catch(err => console.log(err))
console.log(4);
// 1
// 4
// 2
async function foo() {
console.log(1);
await Promise.reject(2).catch(err => console.log(err))
console.log(3);
}
foo()
console.log(4);
// 1
// 4
// 2
// 3
// 调用异步函数foo
//(在foo())中打印1
//(在foo())await关键字暂停执行
// 向消息队列中添加一个任务 foo()退出
// 打印 4
// 同步线程执行完毕
// JS运行时从消息队列取出任务,恢复异步函数执行
//(在foo())恢复执行,await catch输出2
//(在foo())打印4
// foo()返回
async function foo() {
console.log(1);
Promise.reject(2).catch(err => console.log(err))
console.log(3);
}
foo()
console.log(4);
// 1
// 3
// 4
// 2 非重入
实现sleep()
-
以前该需求都通过setTimeout利用js运行时的行为来实现,有了异步函数之后,一个简单的箭头函数即可实现
-
function sleep(delay) { return new Promise((resolve, reject) => setTimeout(resolve, delay)) } async function delayData() { console.log(1); await sleep(2000) console.log(2); } delayData() // 1 等待2s后 2
-