Promise详解
为什么需要Promise
JavaScript是一门单线程语言,所以早期我们解决异步的场景时,大部分情况都是通过回调函数来处理。 例如,在浏览器中发送ajax请求,就是常见的一个异步场景,发送请求后,一段时间服务端响应之后我们才能拿到结果。如果我们希望在异步结束之后执行某个操作,就只能通过回调函数这样的方式进行操作。
const dynamicFunc = function (cb) {
setTimeout(() => {
cb()
}, 1000)
}
dynamicFunc(function () {
console.log(123)
})
上面这个例子中dynamicFunc就是一个异步函数,里面执行的setTimeout会在1s之后将cb函数放入事件队列,待主线程代码执行完后调用cb函数。按照上面的调用方式,最终延迟1s后会打印123这个结果。 同样的,如果后续还有内容需要在异步函数结束时输出的话,就需要多个异步函数进行嵌套,非常不利于后续的维护。
Promise是如何使用的
在支持ES6的高级浏览器环境中,我们通过new Promise()即可创建一个promise实例。
这个构造函数接收一个函数,分别接收两个参数:resolve和reject,代表着改变当前实例的状态为已完成
或者已拒绝
。
function promise1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('1s后输出')
resolve();
}, 1000)
})
}
function promise2() {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log('2s后输出')
resolve();
}, 2000)
})
}
上面两个promise实例,串联起来即可写为:
promise1().then(() => promise2())
也可以简写为:
promise1().then(promise2)
浏览器中执行之后,即可看到,1s之后出现1s后输出
字样,在经过2s出现2s后输出
字样。在这个例子中我们能看到:当前promise如果状态变为已完成(执行了resolve方法),那么就会去执行then方法中的下一个promise函数。
同样的,如果promise变为已拒绝状态(执行了reject方法),那么就会进入后续的异常处理函数中。
function promise3() {
return new Promise(function (resolve, reject) {
var random = Math.random() * 10;
setTimeout(function () {
if (random >= 5) {
resolve(random);
} else {
reject(random);
}
}, 1000);
});
}
var onResolve = function (val) {
console.log('已完成:输出的数字是:', val);
};
var onReject = function (val) {
console.log('已拒绝:输出的数字是:', val);
}
promise3().then(onResolve, onReject);
// 可以通过catch方法拦截状态变为已拒绝的promise
promise3().catch(onReject).then(onResolve);
// 也可以通过try catch 拦截状态变为已拒绝的promise
try {
promise3().then(onResolve);
} catch (e) {
onReject(e);
}
这个例子使用了三种方式拦截最终变为已拒绝
状态的promise,分别使用then的第二个参数,使用.catch方法捕获前方promise抛出的异常,使用try catch拦截代码块中promise抛出的异常
。
同时,我们还发现,在改变promise状态时调用resolve和reject函数的时候,也可以给下一步then中执行的函数传递参数。这个例子中把随机生成的数字传给了resolve和reject函数,我们也就能在then中执行函数的时候拿到这个值。
总结:
- promise会有三种状态,
进行中
已完成
已拒绝
,进行中状态可以更改为已完成或已拒绝,已经更改过状态后无法继续更改(例如不能从已完成改为已拒绝) - ES6中的Promise构造函数,需要传入一个函数,接收两个函数参数,执行第一个参数之后就会改变当前promise为
已完成
状态,执行第二个参数之后就会变为已拒绝
状态 - 通过.then方法,即可在上一个promise变为已完成状态时继续执行下一个函数或promise。同时,通过resolve或reject时传递参数,即可给下一个函数或promise传入初始值
- 已拒绝的promise后续可以通过.catch方法或者.then方法的第二个参数或者try catch进行捕获
promise规范解读
任何符合promise规范的对象或函数都可以成为promise,promises/A+规范地址:https://promisesaplus.com/
上面我们熟悉了整体promise的用法,知道了如何去创建一个promise,如何使用它,也熟悉了如何去改造回调函数到promise。本小节我们详细过一遍promises/A+规范,从规范层面明白Promise使用过程中的细节。
术语
- Promise:promise是一个拥有
then
方法的对象或函数,其行为符合本规范 - 具有then方法(thenable):是一个定义了
then
方法的对象或函数 - 值(value):指任何JavaScript的合法值(包括undefined,thenable和promise)
- 异常(exception):是使用
throw
语句抛出的一个值 - 原因(reason):表示一个promise的拒绝原因
要求
promise的状态
一个Promise的当前状态必须为一下三种状态中的一种:等待态(Pending)、已完成(Fulfilled)、已拒绝(Rejected)。
- 处于等待态时,promise需满足一下条件:可以变为
已完成
或已拒绝
- 处于已完成时,promise需满足一下条件:1.不能改变为其他任何状态 2.必须拥有一个不可变的值
- 处于已拒绝时,promise需满足以下条件:1.不能改变为其他任何状态 2.必须拥有一个不可变的原因
必须有一个then方法
一个promise必须提供一个then
方法以访问其当前值和原因。
promise的then
方法接收两个参数:promise.then(onFulfilled, onRejected)
他们都是可选参数,同时他们都是函数,如果onFulfilled
或onRejected
不是函数,则需要忽略他们。
- 如果
onFulfilled
是一个函数- 当
promise
执行结束后其必须被调用,其第一个参数为promise的结果 - 当
promise
执行结束前其不可被调用 - 其调用次数不可超过一次
- 当
- 如果
onRejected
是一个函数- 当
promise
被拒绝执行后其必须被调用,其第一个参数为promise的原因 - 当
promise
被拒绝执行前其不可被调用 - 其调用次数不可超过一次
- 当
- 在执行上下文堆栈仅包含平台代码之前,不得调用
onFulfilled
或onRejected
onFulfilled
和onRejected
必须被作为普通函数调用(即非实例化调用,这样函数内部this
非严格模式下指向window)then
方法可以被同一个promise
调用多次- 当
promise
成功执行时,所有onFulfilled
需按照其注册顺序依次回调 - 当
promise
被拒绝执行时,所有的onRejected
需按照其注册顺序依次回调
- 当
then
方法必须返回一个promise
对象promise2 = promise1.then(onFulfilled, onRejected)
- 只要
onFulfilled
或onRejected
返回一个值x
,promise2都会进入onFulfilled状态 - 只要
onFulfilled
或onRejected
抛出一个异常e
,则promise2必须拒绝执行,并返回原因e
- 只要
- 如果
onFulfilled
不是函数且promise1
状态变为已完成,promise2
必须成功执行并返回相同的值 - 如果
onRejected
不是函数且promise1
状态变为已拒绝,promise2
必须执行拒绝回调并返回相同的原因
var promise1 = new Promise((resolve, reject) => { reject(); });
promise1
.then(null, function () {
return 123;
})
.then(null, null)
.then(null, null)
.then(
() => {
console.log('promise2已完成');
},
() => {
console.log('promise2已拒绝');
});
promise的解决过程
**promise解决过程是一个抽象的操作,其需输入一个promise
和一个值,我们表示为[[Resolve]](promise, x)
(这句话的意思就是把promise resolve,同时传入x作为值)
promise.then(x => {
console.log('会执行这个函数,同时传入x变量的值: ', x)
})
如果x
有then
方法且看上去像一个Promise,解决程序即尝试使promise
接受x
的状态;否则其用x
的值来执行promise
。
- 如果
promise
和x
指向同一个对象,以TypeError
为原因拒绝执行promise
- 如果
x
为promise
- 如果
x
处于等待态,promise
需保持为等待态直至x
被执行或拒绝 - 如果
x
处于执行态,用相同的值执行promise
- 如果
x
处于拒绝态,用相同的原因拒绝promise
- 如果
var promise1 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1);
resolve();
}, 1000)
});
}
var promise2 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2);
resolve();
}, 2000);
});
}
promise1()
.then(function () {
return promise2(); // 此处返回一个promise实例
})
.then(function () { console.log('已完成') }, function () { console.log('已拒绝') });
- 如果
x
为Object或function(不常见)- 首先尝试执行x.then
- 如果取x.then的值时抛出错误
e
,则以e
为原因拒绝promise
- 如果
then
是函数,将x
作为函数的作用域this
调用。传递两个回调函数作为参数,第一个参数叫做resolvePromise
,第二个叫做rejectPromise
:- 如果
resolvePromise
以值y
为参数被调用,则运行`[[Resolve]](promise, y) - 如果
rejectPromise
以据因r
为参数被调用,则以据因r
拒绝promise
- 如果
resolvePromise
和rejectPromise
均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略其他的调用 - 如果调用
then
方法抛出了异常e
- 如果
resolvePromise
或rejectPromise
已被调用,则忽略 - 否则以
e
为据因拒绝promise
- 如果
- 如果
- 如果
then
不为函数,以x
为参数将promise
变为已完成状态
- 如果
x
不为对象或者函数,以x
为参数将promise
变为已完成状态**(重要且常见)**
Promise构造函数上的静态方法
Promise.resolve
返回一个promise实例,并将它的状态设置为已完成,同时将它的结果作为传入promise实例的值
var promise = Promise.resolve(123);
promise
.then(function (val) {
console.log('???', val);
});
// 已完成 123
同样的,Promise.resolve
的参数也可以处理对象、函数等内容,处理方式和上面规范中介绍的相同。
Promise.reject
返回一个promise实例,并将它的状态设置为已拒绝,同时也将它的结果作为原因传入onRejected函数
var promise = Promise.reject(123);
promise
.then(null, function (val) {
console.log('已拒绝', val);
});
// 已拒绝 123
Promise.all
返回一个promise实例,接收一个数组,里面含有多个promise实例,当所有promise实例都成为已完成状态时,进入已完成状态,否则进入已拒绝状态。
var promise1 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1);
resolve();
}, 1000)
});
}
var promise2 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2);
resolve();
}, 2000);
});
}
Promise.all([promise1(), promise2()])
.then(function () {
console.log('全部promise均已完成');
});
注意,此时多个promise是同时进行的,也就是在上面这个例子中,等待1s打印1之后,在等待1s就会打印打印2和'全部promise均已完成'。
Promise.race
返回一个promise实例,接收一个数组,里面含有多个promise实例,当有一个promise实例状态改变时,就进入该状态且不可改变。这里所有的promise实例为竞争关系,只选择第一个进入改变状态的promise的值。
var promise1 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(1);
resolve(1);
}, 1000)
});
}
var promise2 = function () {
return new Promise(function (resolve) {
setTimeout(function () {
console.log(2);
resolve(2);
}, 2000);
});
}
Promise.race([promise1(), promise2()])
.then(function (val) {
console.log('有一个promise状态已经改变:', val);
});
实现一个简易的promise
Promise类核心逻辑实现
- Promise就是一个类,在对这个类进行实例化的时候要传递一个执行器函数,并且执行器立即执行
- Promise中对应三种状态:成功(fulfilled)失败(rejected)等待(pending)
- 执行resolve方法的时候状态由pending变为fulfilled,执行reject方法的时候状态由pending变为rejected,而且状态一经确定便不可再更改
- then方法定义在原型对象中,接收两个参数分别为成功的回调函数和失败的回调函数
- then方法作用为判断状态,状态成功则调用成功的回调函数(参数表示成功传递的值),状态失败则调用失败的回调函数(参数表示失败的原因)
// 定义常量的目的:1.表示promise的不同状态 2.可以让编辑器有代码提示(哈哈)
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
}
then(successCb, failCb) {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
successCb(this.successData) // 调用成功回调,把值返回
} else if (this.status === REJECTED) { // 同步调用
failCb(this.failReason) // 调用失败回调,把原因返回
}
}
}
const promise = new MyPromise((resolve, reject) => {
resolve('success')
// reject('fail')
});
promise.then(val => {
console.log(val)
}, reason => {
console.log(reason)
})
Promise中加入异步逻辑
上面代码是没有经过异步处理的,如果有异步逻辑则会出现问题
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = undefined // 存储成功的回调函数
failCallback = undefined // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
this.successCallback && this.successCallback(this.successData) // 异步逻辑下调用成功的回调
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
this.failCallback && this.failCallback(this.failReason) // 异步逻辑下调用失败的回调
}
then(successCb, failCb) {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
successCb(this.successData) // 调用成功回调,把值返回
} else if (this.status === REJECTED) { // 同步调用
failCb(this.failReason) // 调用失败回调,把原因返回
} else { // 异步调用
this.successCallback = successCb // 存储成功的回调
this.failCallback = failCb // 存储失败的回调
}
}
}
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
// resolve('success')
reject('fail')
}, 1500)
});
promise.then(val => {
console.log(val)
}, reason => {
console.log(reason)
})
实现Promise then方法被多次调用
- Promise的then方法是可以被多次调用的。
- 下面示例有三个then的回调,如果是同步回调,那么直接返回当前的值就可以。
- 如果是异步回调,那么需要用不同的值保存成功失败的回调,因为互不相同。
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while(this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()(this.successData)
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while(this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
successCb(this.successData) // 调用成功回调,把值返回
} else if (this.status === REJECTED) { // 同步调用
failCb(this.failReason) // 调用失败回调,把原因返回
} else { // 异步调用
this.successCallback.push(successCb) // 存储成功的回调
this.failCallback.push(failCb) // 存储失败的回调
}
}
}
测试示例:
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
// reject('fail')
}, 1500)
});
promise.then(val => {
console.log(val, 11)
}, reason => {
console.log(reason, 11)
})
promise.then(val => {
console.log(val, 22)
}, reason => {
console.log(reason, 22)
})
promise.then(val => {
console.log(val, 33)
}, reason => {
console.log(reason, 33)
})
实现Promise then方法的链式调用
- Promise的then方法是可以被链式调用,后面then方法的回调函数参数值是上一个then方法回调函数的返回值。
- 其中then方法回调函数参数传递包含两种情况:1.参数为普通值 2.参数为另一个promise对象
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()(this.successData)
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
const s = successCb(this.successData) // 调用成功回调,把值返回
// 判断 p 是普通值还是promise对象
// 如果是普通值则直接调用resolve
// 如果是promise对象,则根据promise对象返回结果决定调用resolve还是reject
parsePromiseStatus(s, resolve, reject)
} else if (this.status === REJECTED) { // 同步调用
const f = failCb(this.failReason) // 调用失败回调,把原因返回
parsePromiseStatus(f, resolve, reject)
} else { // 异步调用
this.successCallback.push(successCb) // 存储成功的回调
this.failCallback.push(failCb) // 存储失败的回调
}
})
return promise
}
}
function parsePromiseStatus(p, resolve, reject) {
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
const promise = new MyPromise((resolve, reject) => {
resolve('success') // 目前这里只处理了同步的问题
});
function anther(n) {
return new MyPromise((resolve, reject) => {
resolve('anther' + (n || ''))
})
}
const p = promise.then(val => {
console.log('val: ', val)
// return '2222'
return anther()
}, reason => {
console.log('reason', reason)
return anther(2)
}).then(val => {
console.log('val2: ', val)
}, reason => {
console.log('reason2: ', reason)
})
then方法链式调用识别返回promise对象自身
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
executor(this.resolve, this.reject)
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()(this.successData)
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => { // 使用setTimeout的原因:不使用的话此时方法没执行完毕,不能得到返回值promise
const p = successCb(this.successData) // 调用成功回调,把值返回
// 判断 p 是普通值还是promise对象
// 如果是普通值则直接调用resolve
// 如果是promise对象,则根据promise对象返回结果决定调用resolve还是reject
parsePromiseStatus(promise, p, resolve, reject)
}, 0)
} else if (this.status === REJECTED) { // 同步调用
failCb(this.failReason) // 调用失败回调,把原因返回
} else { // 异步调用
this.successCallback.push(successCb) // 存储成功的回调
this.failCallback.push(failCb) // 存储失败的回调
}
})
return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
const promise = new MyPromise((resolve, reject) => {
resolve('success')
});
const p = promise.then(val => {
console.log(val, 'resolved')
return p
}, reason => {
console.log(reason, 'rejected')
})
p.then(val => {
console.log(val, 22)
}, reason => {
console.log(reason.message)
})
错误捕获
分为两种:1.执行器的错误捕获 2.then执行的时候错误捕获
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()(this.successData)
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()(this.failReason)
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(successCb) // 存储成功的回调
this.failCallback.push(failCb) // 存储失败的回调
}
})
return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
const promise = new MyPromise((resolve, reject) => {
reject('success')
// throw new Error('executor error')
});
promise.then(val => {
console.log(val, 'resolved')
}, reason => {
console.log(reason, 'rejected')
throw new Error('then method error')
}).then(val => {
console.log(val, 'then2')
}, reason => {
console.log(reason.message)
})
异步状态下链式调用——promise异步调用resolve或者reject
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
});
promise.then(val => {
console.log(val, 'resolved')
return 'xxx'
}, reason => {
console.log(reason, 'rejected')
}).then(val => {
console.log(val, 'then2')
}, reason => {
console.log(reason.message)
})
将then方法的参数变为可选参数
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
const promise = new MyPromise((resolve, reject) => {
// resolve('success')
reject('fail')
});
promise.then().then().then(val => {
console.log('resolved: ', val)
}, reason => {
console.log('rejected: ', reason)
})
Promise.all方法的实现
- all方法接收一个数组,数组的每个元素可以是普通值也可以是promise对象
- 数组中元素的顺序就是得到结果的顺序
- 如果数组中所有值是成功的,那么then里面函数就作为成功回调,如果有一个值是失败的,那么then里面函数就作为失败回调
- all方法由类直接调用,那么all肯定是类的静态方法
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
function addArrayEle(key, value) {
result[key] = value
count++
// 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => addArrayEle(i, value), reason => reject(reason))
} else {
// 普通值
addArrayEle(i, current)
}
}
})
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function p2() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 1000)
})
}
MyPromise.all(['a', 'b', p1(), 'c', p2()]).then(val => {
console.log('val: ', val) // ["a", "b", "p1", "c", "p2"]
})
Promise.race方法的实现
- race方法接收一个数组,每个元素可以是普通值也可以是promise对象
- 当存在普通值时,立即返回该值;当所有元素均为promise对象时,如果有一个实例状态改变,就进入该状态且不可改变
- 这里所有的promise实例为竞争关系,只选择第一个进入改变状态的promise值或者普通值
- race方法由类直接调用,那么all肯定是类的静态方法
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
function addArrayEle(key, value) {
result[key] = value
count++
// 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => addArrayEle(i, value), reason => reject(reason))
} else {
// 普通值
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => resolve(value), reason => reject(reason))
} else {
resolve(current)
}
}
})
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 3000)
})
}
function p2() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
reject('p2')
}, 1000)
})
}
MyPromise.race(['b', p1(), 'a', p2()]).then(val => {
console.log('val: ', val); // val: b
}, reason => {
console.log('reason: ', reason)
})
Promise.resolve方法的实现
- 如果参数是一个promise对象,则直接返回;如果是一个值,则生成一个promise对象把值返回
- resolve是类的一个静态方法
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
function addArrayEle(key, value) {
result[key] = value
count++
// 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => addArrayEle(i, value), reason => reject(reason))
} else {
// 普通值
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => resolve(value), reason => reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if(value instanceof MyPromise) {
return value
}
return new MyPromise(resolve => resolve(value))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
MyPromise.resolve(2000).then(val => {
console.log('val: ', val) // 2000
})
MyPromise.resolve(p1()).then(val => {
console.log('val: ', val) // 'p1'
})
Promise.reject方法的实现
- 如果参数是一个promise对象,则直接返回;如果是一个值,则生成一个promise对象把值返回
- resolve是类的一个静态方法
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
function addArrayEle(key, value) {
result[key] = value
count++
// 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => addArrayEle(i, value), reason => reject(reason))
} else {
// 普通值
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => resolve(value), reason => reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
MyPromise.reject(1234).then(null, val => {
console.log('val: ', val) // val: 123
})
finally方法的实现
- 在原型对象上使用,所以不是静态方法
- 无论当前状态是成功还是失败,finally都会执行
- 可以在finally方法之后调用then方法得到结果
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
finally(callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
function addArrayEle(key, value) {
result[key] = value
count++
// 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => addArrayEle(i, value), reason => reject(reason))
} else {
// 普通值
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => resolve(value), reason => reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function p2() {
return new MyPromise((resolve, reject) => {
reject('p1')
})
}
p2().finally(() => {
console.log('finally')
return p1()
}).then(val => {
console.log('resolve: ', val)
}, reason => {
console.log('reject: ', reason)
})
catch方法的实现
- 在原型对象上使用,所以不是静态方法
- 直接调用then方法,第一个参数传递undefined,第二个参数传递reason
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e)
}
}
status = PENDING // 实例属性用来表示promise状态
successData = undefined // 存储成功后resolve传递的参数
failReason = undefined // 存储失败后reject传递的参数
successCallback = [] // 存储成功的回调函数
failCallback = [] // 存储失败的回调函数
resolve = (val) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = FULFILLED // 将状态改为成功
this.successData = val // 存储成功之后的值
while (this.successCallback.length) { // 异步逻辑下调用成功的回调
this.successCallback.shift()()
}
}
reject = (reason) => {
if (this.status !== PENDING) return // 状态为pending时才可继续向下执行
this.status = REJECTED // 将状态改为失败
this.failReason = reason // 存储失败之后的值
while (this.failCallback.length) { // 异步逻辑下调用失败的回调
this.failCallback.shift()()
}
}
then(successCb, failCb) {
successCb = successCb || (value => value) // 有回调使用回调,没回调赋值一个函数
failCb = failCb || (reason => { throw reason })
const promise = new MyPromise((resolve, reject) => {
// 判断状态
if (this.status === FULFILLED) { // 同步调用
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else if (this.status === REJECTED) { // 同步调用
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
} else { // 异步调用
this.successCallback.push(() => {
setTimeout(() => {
try {
const p = successCb(this.successData)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储成功的回调
this.failCallback.push(() => {
setTimeout(() => {
try {
const p = failCb(this.failReason)
parsePromiseStatus(promise, p, resolve, reject)
} catch (e) {
reject(e)
}
}, 0)
}) // 存储失败的回调
}
})
return promise
}
finally(callback) {
return this.then(value => {
return MyPromise.resolve(callback()).then(() => value)
}, reason => {
return MyPromise.resolve(callback()).then(() => { throw reason })
})
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
static all(arr) {
const result = []
let count = 0
return new MyPromise((resolve, reject) => {
function addArrayEle(key, value) {
result[key] = value
count++
// 计数器和数组长度相同,表明所有元素执行完毕,可以输出结果
if (count === arr.length) {
resolve(result)
}
}
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => addArrayEle(i, value), reason => reject(reason))
} else {
// 普通值
addArrayEle(i, current)
}
}
})
}
static race(arr) {
return new MyPromise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
let current = arr[i]
if (current instanceof MyPromise) {
// promise对象
current.then(value => resolve(value), reason => reject(reason))
} else {
resolve(current)
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise) {
return value
}
return new MyPromise(resolve => resolve(value))
}
static reject(reason) {
return new MyPromise((resolve, reject) => reject(reason))
}
}
function parsePromiseStatus(promise, p, resolve, reject) {
if (promise === p) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (p instanceof MyPromise) {
p.then(resolve, reject)
} else {
resolve(p)
}
}
测试示例:
function p2() {
return new MyPromise((resolve, reject) => {
reject('p2 failed')
})
}
p2().then(val => {
console.log('resolve: ', val)
}).catch(reason => {
console.log('fail: ', reason) // fail: p2 failed
})
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!