Promise
使用Promis之前
在介绍Promise之前,需要说一下在没有Promise之前,我们一般是如何处理异步任务的。
如下,以前我们都是使用回调函数的方式来进行处理的,因为在异步函数中,我们是不能直接return得到我们想要的值的。
function requestData(url, successCallback, failureCallback) {
// 模拟网络请求
setTimeout(() => {
if (url === "wyh") {
let result = "请求成功"
successCallback(result)
} else {
let errMessage = "请求失败, url错误"
failureCallback(errMessage)
}
}, 1000);
}
requestData("wyh", (res) => {
console.log(res)
}, (err) => {
console.log(err)
})
note
- 这种回调的方式有很多的弊端:
- 如果是我们自己封装的requestData,那么我们在封装的时候必须要自己设计好callback名称, 并且使用好
- 如果我们使用的是别人封装的requestData或者一些第三方库, 那么我们必须去看别人的源码或者文档, 才知道它这个函数需要怎么去获取到结果
所以有了Promise的诞生,一种更规范/更好的方案(规范好了所有的代码编写逻辑)
Promise基本概念
Promise是一个类,中文可以翻译成 承诺、许诺 、期约。
当我们需要给予调用者一个承诺(比如待会儿我会给你回调数据时),就可以创建一个Promise的对象。在通过new创建Promise对象时,我们需要传入一个函数,我们称之为executor。
- executor会立即执行,并且它会传入另外两个回调函数resolve、reject;
- 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;
- 当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数;
Promise代码结构
const promise = new Promise((resolve, reject) => {
console.log("promise传入的executor被执行了")
// resolve()
// reject()
})
promise.then(res => {
// then方法传入的回调函数, 会在Promise执行resolve函数时, 被回调
console.log(res);
})
promise.catch(err => {
// catch方法传入的回调函数, 会在Promise执行reject函数时, 被回调
console.log(err);
})
Promise尝试
function requestData(url) {
// 异步请求的代码放入到executor中
return new Promise((resolve, reject) => {
// 模拟网络请求
setTimeout(() => {
if (url === "wyh") {
// 成功
let result = "请求成功"
resolve(result)
} else {
// 失败
let errMessage = "请求失败, url错误"
reject(errMessage)
}
}, 1000);
})
}
const promise = requestData("wyh")
// then 也可以一次传入两个回调函数
// 第一个作为是Promise执行resolve的回调,第二个作为Promise执行reject的回调
// 一般都使用这种写法比较多
promise.then((res) => {
console.log(res)
}, (err) => {
console.log(err)
})
Promise的resolve参数
resolve普通的值或者普通对象
const promise = new Promise((resolve, reject) => {
// pending -> fulfilled
resolve('resolve message')
})
resolve一个Promise
那么当前的Promise的状态会由传入的Promise来决定,相当于状态进行了移交
// promise2的状态由promise1决定
const promise1 = new Promise((resolve, reject) => {
resolve('resolve message')
// reject('reject message')
})
const promise2 = new Promise((resolve, reject) => {
// pending -> fulfilled
resolve(promise1)
}).then(res => {
console.log(res)
}, err => {
console.log(err)
})
resolve有then方法的对象(实现了thenable)
那么也会执行该then方法, 并且由该then方法决定后续状态
new Promise((resolve, reject) => {
// pending -> fulfilled
const obj = {
then: function (resolve, reject) {
resolve("resolve message")
// reject("reject message")
}
}
resolve(obj)
}).then(res => {
console.log(res)
}, err => {
console.log(err)
})
Promise对象的then方法
同一个Promise对象可以调用多次then方法
const promise = new Promise((resolve, reject) => {
resolve("resolve message")
})
// 当我们的resolve方法被回调时, 所有的then方法传入的回调函数都会被调用
promise.then(res => {
console.log(res)
})
promise.then(res => {
console.log(res)
})
then方法链式调用
then方法本身是有返回值的,他会返回一个新的Promise,并将resolve回调的返回值作为新Promise的resolve的值
- 如果返回普通值,则作为一个新的Promise的resolve值
const promise = new Promise((resolve, reject) => {
resolve("resolve message")
})
promise.then(res => {
console.log(res) // resolve message
return "a"
}).then(res => {
console.log(res) // a
return "b"
}).then(res => {
console.log(res) // b
}).then(res => {
console.log(res) // undefined
})
- 如果返回的是一个Promise,相当于resolve了一个Promise
const promise = new Promise((resolve, reject) => {
resolve("resolve message")
})
promise.then(res => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('a')
}, 1000)
})
}).then(res => {
console.log(res) // a
})
- 如果返回的是一个对象, 并且该对象实现了thenable,相当于resolve有then方法的对象
const promise = new Promise((resolve, reject) => {
resolve("resolve message")
})
promise.then(res => {
return {
then: function (resolve, reject) {
resolve('a')
}
}
}).then(res => {
console.log(res) // a
})
Promise对象的catch方法
executor抛出异常时, 会调用错误(拒绝)捕获的回调函数的
const promise = new Promise((resolve, reject) => {
throw new Error("error message")
})
promise.then(undefined, err => {
console.log(err)
})
也可以通过catch方法来传入错误(拒绝)捕获的回调函数
note
PromiseA+规范中,没有promise.catch这种规范,是ES6为了使用方便实现的
const promise = new Promise((resolve, reject) => {
throw new Error("error message")
})
promise.catch(err => {
console.log(err)
})
const promise = new Promise((resolve, reject) => {
resolve()
})
promise.then(res => {
throw new Error("error message")
// return new Promise((resolve, reject) => {
// reject("rejected message")
// })
}).catch(err => {
console.log(err)
})
同一个Promise对象可以调用多次catch方法
const promise = new Promise((resolve, reject) => {
reject("rejected message")
})
promise.catch(err => {
console.log(err)
})
promise.catch(err => {
console.log(err)
})
promise.catch(err => {
console.log(err)
})
catch方法的返回值
catch方法本身也是有返回值的,他会返回一个新的Promise,并将catch的返回值作为新Promise的resolve的值
const promise = new Promise((resolve, reject) => {
reject("rejected message")
})
promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err) // rejected message
return "catch return value"
}).then(res => {
console.log(res) // catch return value
}).catch(err => {
console.log(err)
})
Promise对象的finall方法
finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会 被执行的代码。
finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。
const promise = new Promise((resolve, reject) => {
// resolve("resolve message")
reject("reject message")
})
promise.then(res => {
console.log(res)
}).catch(err => {
console.log(err)
}).finally(() => {
console.log("finally code execute")
})
Promise类的resolve方法
前面的then、catch、finally方法都属于Promise的实例方法,都是存放在Promise的prototype上的
有时候我们已经有一个现成的内容了,希望将其转成Promise来使用,则需要通过new Promise来实现
function foo() {
const obj = { name: "wyh" }
return new Promise((resolve) => {
resolve(obj)
})
}
foo().then(res => {
console.log(res)
})
这个时候我们可以使用 Promise.resolve 方法来完成
// 转成Promise对象
const promise = Promise.resolve({ name: "wyh" })
promise.then(res => {
console.log(res)
})
传入一个Promise
const promise = Promise.resolve(new Promise((resolve, reject) => {
resolve("resolve message")
}))
promise.then(res => {
console.log(res) // resolve message
})
传入thenable对象
const promise = Promise.resolve({
then: function (resolve, reject) {
resolve("resolve message")
}
})
promise.then(res => {
console.log(res) // resolve message
})
Promise类的reject方法
无论传入什么值都是一样的,直接reject这个值
const promise = Promise.reject("rejected message")
// 相当于
// const promise = new Promsie((resolve, reject) => {
// reject("rejected message")
// })
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err) // err: rejected message
})
const promise = Promise.reject(new Promise(() => { }))
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err) // err: Promise {<pending>}
})
Promise类的all方法
调用all方法,会在所有的Promise都变成fulfilled时, 再拿到结果,返回的是一个Promise。
返回的是一个数组,结果的顺序是按照传入的顺序返回的
在拿到所有结果之前, 如果有一个Promise变成了rejected, 那么整个Promise就是rejected
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(222)
// reject(222)
}, 2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 3000);
})
// 传入不是promise的值会调用romise.resolve方法,转换成promise
Promise.all([p2, p1, p3, "aaa"]).then(res => {
console.log(res) // [222, 111, 333, 'aaa']
}).catch(err => {
console.log("err:", err)
})
Promise类的allSettled方法
ES11新增的方法,该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是rejected时,才会有最终状态
并且这个Promise的结果一定是fulfilled
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 3000);
})
Promise.allSettled([p1, p2, p3]).then(res => {
console.log(res)
// [
// {
// "status": "fulfilled",
// "value": 111
// },
// {
// "status": "rejected",
// "reason": 222
// },
// {
// "status": "fulfilled",
// "value": 333
// }
// ]
}).catch(err => {
console.log(err) // 不会到catch
})
Promise类的race方法
谁先有结果,那么就使用谁的结果
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 3000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 1500);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 1000);
})
Promise.race([p1, p2, p3]).then(res => {
console.log("res:", res) // res: 333
}).catch(err => {
console.log("err:", err)
})
Promise类的any方法
ES12新增的方法,和race类似,至少等到一个fulfilled状态,才决定promise的状态
如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态
如果所有的Promise都是reject的,那么会报一个AggregateError的错误
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 500);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(333)
}, 3000);
})
Promise.any([p1, p2, p3]).then(res => {
console.log("res:", res) // res: 111
}).catch(err => {
console.log("err:", err.errors)
})
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(222)
}, 500);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(333)
}, 3000);
})
Promise.any([p1, p2, p3]).then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err) // err: AggregateError: All promises were rejected
console.log("err:", err.errors) // err: [111, 222, 333]
})