首先一个实际例子入手
我们调用一个函数,这个函数中发送网络请求(我们可以用定时器来模拟)
如果发送网络请求成功了,那么告知调用者发送成功,并且将相关数据返回过去;
如果发送网络请求失败了,那么告知调用者发送失败,并且告知错误信息;
function requestData(url,successCallback,failureCallback) {
setTimeout(()=>{
if(url==="www.sqda.top") {
// 发送成功
successCallback("请求成功")
} else {
// 发送失败
failureCallback("请求失败")
}
},2000)
}
requestData("www.sqda.top", (res) => {
console.log(res)
}, (err) => {
console.log(err)
})
两秒后打印“请求成功”
什么是Primise?
Promise是一个类,可以翻译成承诺、许诺、期约;
当我们需要给予调用者一个承诺:待会儿我会给你回调数据时,就可以创建一个Promise的对象;
在通过new创建Promise对象时,我们需要传入一个回调函数,我们称之为executor
- 这个回调函数会被立即执行,并且给传入另外两个回调函数resolve、reject;
- 当我们调用resolve回调函数时,会执行Promise对象的then方法传入的回调函数;
- 当我们调用reject回调函数时,会执行Promise对象的catch方法传入的回调函数;
Promise代码结构
const promise=new Promise((resolve,reject)=>{
// 调用resolve,那么then传入的回调会被执行
resolve("success")
// 调用reject,那么catch传入的回调会被执行
reject("failure")
})
promise.then(res=>{
console.log(res); //success
}).catch(err=>{
console.log(err);
})
上面Promise使用过程,我们可以将它划分成三个状态:
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝;当执行executor中的代码时,处于该状态;
- 已兑现(fulfilled): 意味着操作成功完成;执行了resolve时,处于该状态;
- 已拒绝(rejected): 意味着操作失败;执行了reject时,处于该状态;
这里需要注意:一旦状态被确定下来,Promise的状态会被锁死,该Promise的状态是不可更改的
- 在我们调用resolve的时候,如果resolve传入的值本身不是一个Promise,那么会将该Promise的状态变成兑现(fulfilled);
- 在之后我们去调用reject时,已经不会有任何的响应了(并不是这行代码不会执行,而是无法改变Promise状态);
resolve不同值的区别
``* resolve(参数)
``* 1> 普通的值或者对象 pending -> fulfilled
``* 2> 传入一个Promise
``* 那么当前的Promise的状态会由传入的Promise来决定
``* 相当于状态进行了移交
``* 3> 传入一个对象, 并且这个对象有实现then方法(并且这个对象是实现了thenable接口)
``* 那么也会执行该then方法, 并且又该then方法决定后续状态
//1.
new Promise((resolve, reject) => {
resolve("success");
}).then((res) => {
console.log("res:", res);
});
//res: success
//2.
const promise = new Promise((resolve, reject) => {
resolve("success");
})
promise.then(res => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(111111)
}, 3000)
})
}).then(res => {
console.log("res:", res)
})
//res: 111111
//3.
promise.then(res => {
return {
then: function(resolve, reject) {
resolve(222222)
}
}
}).then(res => {
console.log("res:", res)
})
//res: 222222
Promise的对象方法
then方法多次调用
当Promise的状态变成fulfilled的时候,这些回调函数都会被执行;
const promise = new Promise((resolve, reject) => {
resolve("success");
})
promise.then(res => {
console.log(res,111);
})
promise.then(res => {
console.log(res,222);
})
promise.then(res => {
console.log(res,333);
})
//success 111
//success 222
//success 333
then方法----返回值
-
hen方法本身是有返回值的,它的返回值是一个Promise,所以我们可以进行如下的链式调用
-
Promise有三种状态,那么这个Promise处于什么状态呢
当then方法中的回调函数本身在执行的时候,那么它处于pending状态;
p当then方法中的回调函数返回一个结果时,那么它处于fulfilled状态,并且会将结果作为resolve的参数;
- 返回一个普通值
- 返回一个Promise
- 返回一个thenable值
-
当then方法抛出一个异常时,那么它处于reject状态;
catch方法–多次调用
和then一个意思
const promise = new Promise((resolve, reject) => {
reject("fail");
})
promise.catch(res => {
console.log(res,111);
})
promise.catch(res => {
console.log(res,222);
})
promise.catch(res => {
console.log(res,333);
})
//fail 111
//fail 222
//fail 333
catch方法–返回值
const promise = new Promise((resolve, reject) => {
reject("fail");
})
promise.catch(res => {
console.log(res,111);
}).catch(err=>{
console.log(err,222);
}).then(res=>{
console.log(res,333);
})
//fail 111
//undefined 333
为什么不会打印222那行代码呢?
因为catch传入的回调在执行完后,默认状态依然会是fulfilled的;
如果我们希望继续执行catch,那么需要抛出一个异常
const promise = new Promise((resolve, reject) => {
reject("fail");
})
promise.catch(res => {
console.log(res,111);
throw new Error("error message")
}).catch(err=>{
console.log(err,222);
}).then(res=>{
console.log(res,333);
})
// fail 111
// Error: error message
// ..... 222
// undefined 333
finally方法
finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。
const promise = new Promise((resolve, reject) => {
// resolve("resolve message")
reject("reject message")
})
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
}).finally(() => {
console.log("finally code execute")
})
// err: reject message
// finally code execute
Promise类方法
resolve
const promise = Promise.resolve({ name: "why" })
// 相当于
const promise2 = new Promise((resolve, reject) => {
resolve({ name: "why" })
})
promise2.then(res=>{
console.log(res);
})
//{ name: 'why' }
reject
const promise = Promise.reject(new Promise(() => {}))
promise.then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
all
它的作用是将多个Promise包裹在一起形成一个新的Promise;
新的Promise状态由包裹的所有Promise共同决定:
1.当所有的Promise状态变成fulfilled状态时,新的Promise状态为fulfilled,并且会将所有Promise的返回值组成一个数组;
2.当有一个Promise状态为reject时,新的Promise状态为reject,并且会将第一个reject的返回值作为参数;
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(11111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(22222)
}, 2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(33333)
}, 3000);
})
// 需求: 所有的Promise都变成fulfilled时, 再拿到结果
// 意外: 在拿到所有结果之前, 有一个promise变成了rejected, 那么整个promise是rejected
Promise.all([p2, p1, p3, "aaaa"]).then(res => {
console.log(res)
}).catch(err => {
console.log("err:", err)
})
//[ 22222, 11111, 33333, 'aaaa' ]
allSettled
该方法会在所有的Promise都有结果(settled),无论是fulfilled,还是reject时,才会有最终的状态;
p并且这个Promise的结果一定是fulfilled的;
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(11111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(22222)
}, 2000);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(33333)
}, 3000);
})
// allSettled
Promise.allSettled([p1, p2, p3]).then(res => {
console.log(res)
}).catch(err => {
console.log(err)
})
// [
// { status: 'fulfilled', value: 11111 },
// { status: 'rejected', reason: 22222 },
// { status: 'fulfilled', value: 33333 }
// ]
race
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(11111)
}, 3000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(22222)
}, 500);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(33333)
}, 1000);
})
// race: 竞技/竞赛
// 只要有一个Promise变成fulfilled状态, 那么就结束
Promise.race([p1, p2, p3]).then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err)
})
//err: 22222
any
- any方法会等到一个fulfilled状态,才会决定新Promise的状态;
- 如果所有的Promise都是reject的,那么也会等到所有的Promise都变成rejected状态;
- 如果所有的Promise都是reject的,那么会报一个AggregateError的错误。
// 创建多个Promise
const p1 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(11111)
reject(1111)
}, 1000);
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(22222)
}, 500);
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve(33333)
reject(3333)
}, 3000);
})
// any方法
Promise.any([p1, p2, p3]).then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err.errors)
})
//err: [ 1111, 22222, 3333 ]
手写Promise
// ES6 ES2015
// https://promisesaplus.com/
const PROMISE_STATUS_PENDING = 'pending'
const PROMISE_STATUS_FULFILLED = 'fulfilled'
const PROMISE_STATUS_REJECTED = 'rejected'
// 工具函数
function execFunctionWithCatchError(execFn, value, resolve, reject) {
try {
const result = execFn(value)
resolve(result)
} catch(err) {
reject(err)
}
}
class HYPromise {
constructor(executor) {
this.status = PROMISE_STATUS_PENDING
this.value = undefined
this.reason = undefined
this.onFulfilledFns = []
this.onRejectedFns = []
const resolve = (value) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_FULFILLED
this.value = value
this.onFulfilledFns.forEach(fn => {
fn(this.value)
})
});
}
}
const reject = (reason) => {
if (this.status === PROMISE_STATUS_PENDING) {
// 添加微任务
queueMicrotask(() => {
if (this.status !== PROMISE_STATUS_PENDING) return
this.status = PROMISE_STATUS_REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => {
fn(this.reason)
})
})
}
}
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
const defaultOnRejected = err => { throw err }
onRejected = onRejected || defaultOnRejected
const defaultOnFulfilled = value => { return value }
onFulfilled = onFulfilled || defaultOnFulfilled
return new HYPromise((resolve, reject) => {
// 1.如果在then调用的时候, 状态已经确定下来
if (this.status === PROMISE_STATUS_FULFILLED && onFulfilled) {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
}
if (this.status === PROMISE_STATUS_REJECTED && onRejected) {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
}
// 2.将成功回调和失败的回调放到数组中
if (this.status === PROMISE_STATUS_PENDING) {
if (onFulfilled) this.onFulfilledFns.push(() => {
execFunctionWithCatchError(onFulfilled, this.value, resolve, reject)
})
if (onRejected) this.onRejectedFns.push(() => {
execFunctionWithCatchError(onRejected, this.reason, resolve, reject)
})
}
})
}
catch(onRejected) {
return this.then(undefined, onRejected)
}
finally(onFinally) {
this.then(() => {
onFinally()
}, () => {
onFinally()
})
}
static resolve(value) {
return new HYPromise((resolve) => resolve(value))
}
static reject(reason) {
return new HYPromise((resolve, reject) => reject(reason))
}
static all(promises) {
// 问题关键: 什么时候要执行resolve, 什么时候要执行reject
return new HYPromise((resolve, reject) => {
const values = []
promises.forEach(promise => {
promise.then(res => {
values.push(res)
if (values.length === promises.length) {
resolve(values)
}
}, err => {
reject(err)
})
})
})
}
static allSettled(promises) {
return new HYPromise((resolve) => {
const results = []
promises.forEach(promise => {
promise.then(res => {
results.push({ status: PROMISE_STATUS_FULFILLED, value: res})
if (results.length === promises.length) {
resolve(results)
}
}, err => {
results.push({ status: PROMISE_STATUS_REJECTED, value: err})
if (results.length === promises.length) {
resolve(results)
}
})
})
})
}
static race(promises) {
return new HYPromise((resolve, reject) => {
promises.forEach(promise => {
// promise.then(res => {
// resolve(res)
// }, err => {
// reject(err)
// })
promise.then(resolve, reject)
})
})
}
static any(promises) {
// resolve必须等到有一个成功的结果
// reject所有的都失败才执行reject
const reasons = []
return new HYPromise((resolve, reject) => {
promises.forEach(promise => {
promise.then(resolve, err => {
reasons.push(err)
if (reasons.length === promises.length) {
reject(new AggregateError(reasons))
}
})
})
})
}
}
const p1 = new Promise((resolve, reject) => {
setTimeout(() => { reject(1111) }, 3000)
})
const p2 = new Promise((resolve, reject) => {
setTimeout(() => { reject(2222) }, 2000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => { reject(3333) }, 3000)
})
// HYPromise.race([p1, p2, p3]).then(res => {
// console.log("res:", res)
// }).catch(err => {
// console.log("err:", err)
// })
HYPromise.any([p1, p2, p3]).then(res => {
console.log("res:", res)
}).catch(err => {
console.log("err:", err.errors)
})