Promise含义
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise基本结构
》》》 目标
const p = new Promise((resolve, reject) => {
if ('异步操作成功'){
resolve('成功了');
} else {
reject('失败了');
}
})
Promise是一个构造函数,必须接收一个函数作为参数,我们称该函数为executor(执行器),executor又包含了两个函数作为参数,分别是resolve和reject,当异步操作成功后马上执行resolve,异步操作失败后,会马上执行reject
》》》代码实现
class MyPromise{
constructor(executor){
if(typeof executor !== 'function') {
throw new Error('MyPromise必须接收一个函数作为参数')
}
// 执行传进来的函数executor
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch(err) {
this.reject(err)
}
}
resolve(){}
reject(){}
}
Promise中有throw的话,就相当于执行了reject。这就要使用try catch了
为什么要绑定this呢?这是为了resolve和reject的this指向永远指向当前的MyPromise实例,防止随着函数执行环境的改变而改变
Promise状态和值
状态
Promise有三种状态,分别是Pending(等待中),Fulfilled(已成功),Rejected(已失败)。
状态只能由Pending变成Fulfilled, 或由Pending变成Rejected,且状态确定后不会再发生变化(不能再次修改)。
值
Promise的值是指异步操作完成(状态改变)后传给回调函数的值。如上文,executor接收的两个函数resolve和reject就是用来改变状态和传递值的,resolve传递操作成功的值,reject传递操作失败的值
》》》代码实现
// 定义三种状态常量
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'reject'
class MyPromise{
status = PENDING // 设置初始状态
value = undefined // 设置初始值
constructor(executor){
if(typeof executor !== 'function') {
throw new Error('MyPromise必须接收一个函数作为参数')
}
// 执行executor
try {
executor(this.resolve.bind(this), this.reject.bind(this))
} catch(err) {
this.reject(err)
}
}
resolve(val){
if (this.status !== PENDING) return
this.status = FULFILLED // 修改状态
this.value = val // 修改值
}
reject(err){
if (this.status !== PENDING) return
this.status = REJECT // 修改状态
this.value = err // 修改值
}
}
Promise核心:then方法
-
Promise 实例具有
then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。 -
Promise实例化时传入的函数会立即执行,then(...)中的回调需要异步延迟调用。
then基本使用
》》》目标
p.then(onFulfilled, onRejected)
》》》 代码实现
then(onFulfilled, onRejected) { // 异步操作完成修改状态后被调用, 根据状态决定调用的函数
if (this.status === FULFILLED) onFulfilled(this.value)
if (this.status === REJECTED) onRejected(this.value)
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
}
》》》 使用
const p1 = new MyPromise((resolve, reject) => {
resolve('成功了');
})
p1.then(res => console.log(res), err => console.log(err)) // 成功了
const p2 = new MyPromise((resolve, reject) => {
reject('失败了');
})
p2.then(res => console.log(res), err => console.log(err)) // 失败了
then链式调用
-
then方法接收两个可选参数
onFulfilled和onRejected,参数必须是函数 -
then方法返回的是一个新的Promise实例(注意,不是原来那个Promise实例)。因此可以采用链式写法,即then方法后面再调用另一个then方法。 -
下一个then接收的参数就是上一个then返回的结果,上一个then没有返回值,则下一个then接收的是undefined
》》》 目标
p.then(function(){}, function(){})
.then(function(){}, function(){})
.then(function(){}, function(){})
》》》 代码实现
// 异步操作完成修改状态后被调用,
then(onFulfilled, onRejected) {
// 定义一个新的promise对象,因为then需要返回一个新的promise对象,才能被then链式调用
const thenPromise = new Promise((resolve, reject) => {
// 根据状态决定调用的函数
if (this.status === FULFILLED) resolve(onFulfilled(this.value))
if (this.status === REJECTED) reject(onRejected(this.value))
// 等待状态则不能马上调用,先把回调存起来,等状态不是PENDING时再调用
if (this.status === PENDING) {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
})
//返回一个新的Promise对象
return thenPromise
}
》》》 使用
p.then((res) => { return 'result1' }, (err) => {})
.then((res) => { console.log(res) }, (err) => {}) // 'result1'
.then((res) => { console.log(res) }, (err) => {}) // 'undefined'
.then((res) => { throw new Error('错误') }, (err) => {})
.then((res) => { }, (err) => { console.log(err) }) // Error: 错误
Promise类中处理异步逻辑(如定时器)
》》》 目标
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('异步setTimeout成功~~~!')
reject('异步setTimeout成功~~~!')
}, 1000)
})
p.then(res => console.log(res), err => console.log(err)) // '异步setTimeout成功~~~!'
处理异步逻辑时,可以先把then里的两个回调保存起来,等状态不是pending,就证明定时器/异步逻辑已执行完。建议使用数组保存这些回调,因为一个promise实例可能会有多次then
》》》代码实现
onFulfilledCallbacks = [] // 保存成功回调
onRejectedCallbacks = [] // 保存失败回调
resolve(val){
if (this.status !== PENDING) return
this.status = FULFILLED
this.value = val
// 执行保存的成功回调
while (this.onFulfilledCallbacks.length) {
this.onFulfilledCallbacks.shift()(this.value)
}
}
reject(err){
if (this.status !== REJECTED) return
this.status = REJECTED
this.value = err
// 执行保存的失败回调
while (this.onRejectedCallbacks.length) {
this.onRejectedCallbacks.shift()(this.value)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) onFulfilled(this.value)
if (this.status === REJECTED) onRejected(this.value)
if (this.status === PENDING) {
// 处理异步待定状态,暂时保存两个回调
this.onFulfilledCallbacks.push(onFulfilled.bind(this))
this.onRejectedCallbacks.push(onRejected.bind(this))
}
}
Promise.all
all 接收的一个以Promise实例组成的数组,等待所有Promise实例执行成功,返回一个Promise实例传递数组结构的结果; 但凡其中有一个Promise实例操作失败,返回失败结果
》》》目标
1. 所有异步执行成功
const p1 = new Promise(resolve => resolve('resut1'))
const p2 = new Promise(resolve => resolve('resut2'))
const p3 = new Promise(resolve => resolve('resut3'))
const p4 = '123'
const all = Promise.all([p1, p2, p3, p4])
all.then(res => console.log(res)) // [ 'resut1', 'resut2', 'resut3', '123' ]
2、异步操作有失败的
const p1 = new Promise(resolve => resolve('resut1'))
const p2 = new Promise((resolve, reject) => reject('error2'))
const p3 = new Promise(resolve => resolve('resut3'))
Promise.all([p1, p2,p3]).then(res => console.log(res)).catch(err => console.log(err)) // 'error2'
》》》 代码实现
static all (arr) { // 接收一个数组
if(!isArray(arr)) {
throw new Error('all 需要传递一个数组类型')
}
const allPromise = new MyPromise((resolve, reject) => {
const newArr = []
for(let i = 0; i<arr.length; i++){
if(arr[i] instanceof MyPromise) {
arr[i].then(success => {
newArr.push(success)
}, error => {
reject(error)
})
} else {
// 数组元素是非Promise实例的,直接放到数组里
newArr.push(arr[i])
}
i === arr.length - 1 && (resolve(newArr)) // 判断是否已经完成
}
})
// 返回一个新的Promise实例,传递数组结构的结果
return allPromise
}
》》》使用
const p1 = new MyPromise(resolve => resolve('resut1'))
const p2 = new MyPromise((resolve, reject) => reject('error2'))
const p3 = new MyPromise(resolve => resolve('resut3'))
const p4 = '123'
MyPromise.all([p1, p3, p4]).then(res => console.log(res), err => console.log(err)) // [ 'resut1', 'resut3', '123' ]
MyPromise.all([p1, p2, p3, p4]).then(res => console.log(res), err => console.log(err)) // 'error2'
Promise.race
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
》》》目标
const p1 = new Promise(resolve => resolve('resut1'))
const p2 = new Promise(resolve => resolve('resut2'))
const p3 = new Promise(reject => reject('resut3'))
Promise.race([p1, p2, p3]).then(res => {
console.log('success:', res);
}, err => {
console.log('error:', err);
})
// success: resut1
》》》代码实现
static race(arr) { // 接收一个数组,数组元素必须是Promise实例,数组中但凡有一个操作执行成功/失败,就马上返回结果
const racePromise = new MyPromise((resolve, reject) => {
if(!isArray(arr)) {
reject('race 需要传递一个数组类型')
return
}
if (!arr.every(v => v instanceof MyPromise)){
reject('race 需要传递一个由MyPromise实例组成的数组')
return
}
const resulrArr = []
for(let i = 0; i<arr.length; i++){
if (resulrArr.length > 0) {
resolve(resulrArr[0])
return
}
arr[i].then(success => {
resulrArr.push(success)
}, error => {
resulrArr.push(error)
})
}
})
// 返回一个新的Promise实例,传递第一个操作完成的返回结果(成功/失败)
return racePromise
}
》》》使用
const p1 = new MyPromise(resolve => resolve('resut1'))
const p2 = new MyPromise((resolve, reject) => reject('error2'))
const p3 = new MyPromise(resolve => resolve('resut3'))
const p4 = '123'
MyPromise.race([p1, p2, p3]).then(res => {
console.log('success:', res);
}, err => {
console.log('error:', err);
})
// success: resut1
MyPromise.race([p1, p2, p3, p4]).then(res => {
console.log('success:', res);
}, err => {
console.log('error:', err);
})
// error: race 需要传递一个由MyPromise实例组成的数组
Finally
- 在 promise 执行完毕后无论其结果怎样都做一些处理或清理时,
finally()方法可能是有用的 - 由于无法知道
promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
》》》 目标
const p = new Promise((resolve, reject) => {
resolve('操作成功!')
reject('操作成功!')
})
p.then(res => console.log(res)).finally(() => console.log('操作结束'))
// 操作成功!
// 操作结束
》》》代码实现
onFinallyCallbacks = []
finally(onFinally) {
if(typeof onFinally !== 'function') throw new Error('MyPromise finally方法接收的参数必须是函数')
const finallyPromise = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED || this.status === REJECTED) {
resolve(onFinally)
}
if (this.status === PENDING){
this.onFinallyCallbacks.push(onFinally)
}
})
return finallyPromise
}
》》》使用
const p = new MyPromise((resolve, reject) => {
resolve('操作成功!')
reject('操作成功!')
})
p.then(res => console.log(res)).finally(() => console.log('操作结束'))
// 操作成功!
// 操作结束