一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情。
Promise简介
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise的特点
- 对象的状态不受外界影响。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)。只有在Promsie内部调用resolve 或 reject,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。如果改变已经发生了,你再对Promise对象添加回调函数,也会立即得到这个结果。
Promise的缺点
- Promise对象一旦新建就会立即执行,无法中途取消
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)
Promise的状态
使用new Promise
创建的promise对象有三个状态
- Fulfilled
-
- 成功状态,此时会调用 onFulfilled回调
- Rejected
-
- 失败状态, 此时会调用 onRejected 回调
- pending
-
- Promise对象被创建后的初始状态
\
基本用法
Promise对象是一个类,用来生成Promise实例。
下面代码创造了一个Promise实例。
const promise = new Promise((resolve, reject) => {
//一些异步操作代码
if('异步操作成功'){
resolve(value)
}else{
reject(err)
}
})
Promise类接受一个函数作为参数,这个函数我们称之为执行器,在传入之后会立即执行。该函数的两个参数分别是resolve和reject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
Promise实例生成以后,如何Promise对象传出的值?
一、 实例.then() 中传入两个回调函数
promise.then(val => {
//成功回调
}, err => {
//失败回调
})
then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。
二、实例.then().catch()
promise.then(res => {
//成功回调
}
).catch(err => {
//失败回调
})
then表示成功回调, catch表示失败回调
手写Promise
下面我们通过手写promise的方式来加深理解,如有错误的地方,烦请指正,一起进步
核心逻辑实现
- Promise是一个类,在创建时会传入一个函数,这个函数会立即执行
//将Promise的三个状态定义为常量,修改时不必手敲单词,编辑器会有提示
const PENDING = 'pending',
FULFILLED = 'fulfilled',
REJECTED = 'rejected'
class MyPromise{
constructor(executor){
//在constructor中立即执行传入的函数
executor(this.resolve, this.reject)
}
//初始状态是等待
status = PENDING
//resolve和reject是在创建实例时直接调用的,要用箭头函数将this绑定给当前实例
resolve = () => {
}
reject = () => {
}
}
- Promise有三种状态, 分别为: 成功fulfilled, 失败rejected, 等待pending
pending -> fulfilled
pending -> rejected
状态只能有上面两种变化方式,且状态一旦更改便不可再次更改,resolve和reject是用来更改Promise状态的
因此,resolve和reject中分别这样写
class MyPromise{
...
status = PENDING
resolve= () => {
if(this.status !== PENDING) return
this.status == FULDILLED
}
reject = () => {
if(this.status !== PENDING) return
this.status == REJECTED
}
...
}
- then 方法内部做的事情就是判断状态, 如果是成功就调用成功的回调函数, 失败就调用失败的回调函数,then方法时被定义在原型对象上的方法
then成功回调有一个参数表示成功的值(调用resolve时传入的值), 失败回调有一个参数表示失败的原因(调用reject时传入的值)
class MyPromise{
...
status = PENDING
value = undefined
resaon = undefined
resolve= (value) => {
//判断状态
if(this.status !== PENDING) return
this.status == FULDILLED
//保存成功的值
this.value = value
}
reject = (reason) => {
//判断状态
if(this.status !== PENDING) return
this.status == REJECTED
//保存失败的值
this.reason = reason
}
//在调用then方法时会传入成功和失败的回调
then(successCallback, failCallback){
//首先判断状态
//然后我们发现then方法成功失败回调的参数此时没有,其实他们就是调用resolve和reject时传入的值
if(this.status == FULFILLED){
successCallback(this.value)
}else if(this.status == REJECTED){
failCallback(this.reason)
}
}
...
}
核心逻辑完整代码
const PENDING = 'pending',
FULFILLED = 'fulfilled',
REJECTED = 'rejected'
class MyPromise{
constructor(executor){
executor(this.resolve, this.reject)
}
status = PENDING
value = undefined
reason = undefined
resolve = (value) => {
if(this.status !== PENDING) return
this.status = FULFILLED
this.value = value
}
reject = (reason) => {
if(this.status !== PENDING) return
this.stauts = REJECTED
this.reason = reason
}
then(successCallback, failCallback){
if(this.status == FULFILLED){
successCallback(this.value)
}else if(this.status == REJECTED){
failCallback(this.reason)
}
}
}
处理异步逻辑
问题分析
使用自己写的promise模拟一下异步操作:
首次,导出我们写的MyPromise类
class MyPromise{
.....
}
//使用node运行,所以用commonJS规范导出
module.exports = MyPromise
同一目录下,新建一个js文件 导入MyPromise类
const MyPromise = require('./myPromise')
let mp = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
},2000)
})
mp.then(res => {
console.log(res)
})
运行结果:
我们可以看到,什么都没有输出, 原因如下:
- then方法是同步的,会自上而下立即执行
- 而resolve在2S之后异步执行的,2S之后才会将promise状态改为成功
- then方法中只判断了成功和失败,并没有判断等待的状态
- 因此对于异步的resolve和reject,then方法中的状态依旧是等待,什么都不会执行
修改代码
1、在当前实例中添加两个属性,接收成功回调和失败回调
2、then方法中添加当前状态是等待时的处理,将传入的成功回调和失败回调分别赋值给实例的两个属性
3、当调用resolve时,执行当前实例的成功回调
调用reject时, 执行当前实例的失败回调
class MyPromise {
....
resolve = (value) => { //将状态改为成功
if(this.status !== PENDING) return
this.status = FULFILLED
//保存成功之后的值
this.value = value
//调用当前实例保存的成功回调 并传入参数
this.successCallback && this.successCallback(this.value)
}
reject = (reason) => { //将状态改为失败
if(this.status !== PENDING) return
this.status = REJECTED
// 保存失败的原因
this.reason = reason
//调用当前实例的失败回调 并传入参数
this.failCallback && this.failCallback(this.reason)
}
//存储成功回调和失败回调
successCallback = null
failCallback = null
then(successCallback, failCallback){
if(this.status === FULFILLED){ //状态是成功
successCallback(this.value)
}else if(this.status === REJECTED){ //状态是失败
failCallback(this.reason)
}else{ //状态是等待时,将传进来的处理函数保存在当前实例内
this.successCallback = successCallback
this.failCallback = failCallback
}
}
....
}
再次运行下当前出现问题的代码:
可以看到,在2S后输出了成功,代码修改完成
\
then方法多次调用
问题分析
我们前面说过,Promise状态一旦改变,便不会再次改变。任何时候都可以得到这个结果
是不是意味着,我们可以多次通过.then的方式,传入不同的处理函数来处理Promise的结果
此时就会出现一个问题:
- 如果是同步调用resolve或reject, 我们在调用then方法时,直接执行传入的处理函数即可,但是我们Promise一般都是来处理异步操作的
- 处理异步操作时, 如果多次调用then方法,我们内部保存的成功和失败回调一定会被最后一次调用then时传入的回调函数覆盖, 也只会执行最后一次回调函数
const MyPromise = require('./myPromise')
new Promise((resolve, reject) => {
resolve('成功')
})
let mp = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
})
mp.then(res => {
console.log(res + '1')
})
mp.then(res => {
console.log(res + '2')
})
mp.then(res => {
console.log(res + '3')
})
输出:
\
修改代码
1、修改MyPromise类中保存成功失败回调函数属性的数据类型
之前是直接then中传递来的成功失败回调为它们赋值
现将它们改为数组, 每次调用then方法,就将回调函数添加到数组中
class MyPromise{
...
successCallback = []
failCallback = []
}
2、调用then方法时,将传递进来的回调函数push到MyPromise内部的回调数组中
class MyPromise{
...
successCallback = []
failCallback = []
...
then(successCallback, failCallback){
//判断状态
if(this.status == FULFILLED){
successCallback(this.value)
}else if(this.status == REJECTED){
failCallback(this.reason)
}else{ //状态为等待,向MyPromise内部保存回调函数的数组中添加传入的回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
}
}
3、调用resolve或reject时
class MyPromise{
...
status = PENDING
value = undefined
reason = undefined
successCallback = []
failCallback = []
...
resolve = (value) => {
//按照先进先出的顺序 执行successCallback中传入的成功回调
while(this.successCallback.length){
this.successCallback.pop()(value)
}
}
reject = (reason) => {
//按照先进先出的顺序,执行failCallback中传入的失败回调
while(this.failCallback.length){
this.failCallback.shift()(reason)
}
}
then(successCallback, failCallback){
//判断状态
if(this.status == FULFILLED){
successCallback(this.value)
}else if(this.status == REJECTED){
failCallback(this.reason)
}else{ //状态为等待,向MyPromise内部保存回调函数的数组中添加传入的回调函数
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
}
}
再次执行上面多次调用then方法的代码
现在可以看到2s后一次执行了我们传入的处理函数
then方法链式调用
我们知道,promise的then方法支持链式调用, 后面一个then方法拿到的值 是 上一个then方法返回的值
例:
let mp = new MyPromise((resolve, reject) => {
resolve(123)
})
mp.then(res => {
console.log(res)
return 234
}).then(res => {
console.log(res)
})
要实现链式调用,需要做到以下两点:
- then方法的链式调用,我们知道,只有promise对象才有then方法, 因此每一个then方法都应该返回一个promise对象
- 将上一个then方法的返回值传递给下一个then方法
需求1,then方法的链式调用
class MyPromise{
...
then(successCallback, failCallback) {
//在then方法中创建一个promise对象并返回
// 创建promise对象时,传入的函数,会立即执行
// 而我们then方法中原来的代码也需要立即执行,因此直接将then中原有的代码,放入返回的promise对象传入的函数中
const promise2 = new MyPromise((resolve, reject) => {
//判断状态
if(this.status == FULFILLED){
successCallback(this.value)
}else if(this.status == REJECTED){
failCallback(this.reason)
}else{ //状态为等待,处理异步逻辑
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
...
}
需求2、将上一个then方法的返回值传递给下一个then方法
class MyPromise{
...
then(successCallback, failCallback) {
const promise2 = new MyPromise((resolve, reject) => {
if(this.status == FULFILLED){
//用一个变量去接收上个then返回的值
let x = successCallback(this.value)
//直接调用返回的promise的resolve方法,
resolve(x)
}else if(this.status == REJECTED){
failCallback(this.reason)
}else{
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
...
}
此时看起来代码就差不多了,但是我们忽略了一个问题, 上一个then方法可以返回一个普通值,也可以返回一个promise对象
- 当上一个then方法返回一个普通值时,我们直接返回一个promise对象是没问题的
- 当上一个then方法返回一个promise对象时, 我们需要去判断状态返回的promise对象的状态,从而确定使用成功还是失败回调
class MyPromise{
...
then(successCallback, failCallback) {
const promise2 = new MyPromise((resolve, reject) => {
if(this.status == FULFILLED){
//用一个变量去接收上个then返回的值
//判断x的类型是普通值还是promise对象
//如果是普通值,直接调用返回的promise对象的resolve方法
//如果是promise对象,确定promise对象返回的结果
//在根据promise对象返回的结果,决定调用resolve还是reject
let x = successCallback(this.value)
resolvePromise(x, resolve, reject)
}else if(this.status == REJECTED){
failCallback(this.reason)
}else{
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
...
}
//定义通用函数,处理上一个then返回值的类型,被确定下一个then中调用成功回调还是失败回调
function resolvePromise(x, resolve, reject){
if(x instanceof MyPromise){ //x 是promise对象
x.then(val => resolve(val), reason => reject(reason))
}else{ //x是普通值
resolve(x)
}
}
测试代码:
let mp = new MyPromise((resolve, reject) => {
resolve(123)
})
function other() {
return new MyPromise((resolve, reject) => {
resolve('other')
})
}
mp.then(res => {
console.log(res)
return other()
}).then(res => {
console.log(res)
})
看下结果:
完成!
then方法识别是否返回自身
\
我们在then方法的链式调用中,是不能返回自身的promise对象的
用JS给我们提供的Promise类模拟一下:
const p = new Promise((resolve, reject) => {
resolve('Promise')
})
let p1 = p.then(res => {
console.log(res)
// 我们知道 p.then方法返回的一定是一个promise对象
//用p1去接收返回的promise对象
//而又将返回的promsie对象return了出去
//此时就会发生promise对象的循环调用,控制台就会抛出错误
return p1
})
运行代码,可以看到控制台出现以下报错信息:
大意是:promise对象被循环调用了,这样是不可以的
如何在我们写的程序中判断返回的promise对象是不是自身?
回到我们的then方法中
class MyPromise{
...
then(successCallback, failCallback) {
//promise2是我们要返回的promise对象
const promise2 = new MyPromise((resolve, reject) => {
if(this.status == FULFILLED){
//只有当new MyPromise执行结束,才会存在promise2,因此将这段代码变为异步执行
setTimeout(() => {
//x是上一个.then返回的值
//我们只要判断promise2 是否=== x 即可
let x = successCallback(this.value)
//将判断是否相等操作统一给到resolvePromise处理
//将promise2传入resolvePromise中
resolvePromise(promise2, x, resolve, reject)
},0)
}else if(this.status == REJECTED){
failCallback(this.reason)
}else{
this.successCallback.push(successCallback)
this.failCallback.push(failCallback)
}
})
return promise2
}
...
}
function resolvePromise(promise2, x, resolve, reject){
//如果相等,抛出类型错误
if(promise2 === x){
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof MyPromise){ //x 是promise对象
x.then(val => resolve(val), reason => reject(reason))
}else{ //x是普通值
resolve(x)
}
}
使用我们写的MyPromise看下效果:
const promise = new MyPromise((resolve, reject) => {
resolve('Promise')
})
let p1 = promise.then(res => {
console.log(res)
return p1
})
p1.then(
res => {
console.log(res)
},
err => { //失败回调
console.log(err)
}
)
输出结果:
我们可以看到,由于返回了自身, 我们在p1的then方法的失败回调中得到了错误信息
运行时错误捕获及then方法链式调用完整化
在promise中,当执行器当中的代码在执行时发生错误 或 then方法回调函数中抛出错误时,都是可以捕获到的,从而在失败回调中拿到结果
\
例:
const promise = new Promise((resolve, reject) => {
throw new Error('executor error') //模拟promise等待状态中运行时发生错误
resolve('promise')
}).then(res => {
console.log(res)
}, err => {
console.log('onRejected')
console.log(err.message)
throw new Error('then方法抛出错误')
}).then(res => {
console.log(res)
}, err => {
console.log('onRejected1')
console.log(err.message)
})
执行结果:
\
接下来修改代码,实现错误捕获:
1、 执行器中错误捕获
class MyPromise {
constructor(executor){
try {
//尝试去执行 执行器
executor(this.resolve, this.reject)
}catch(err){
//执行器执行过程中遇到错误对象,直接调用reject,并传入错误对象
this.reject(err)
}
}
}
2、捕获then方法回调函数中抛出的错误
当then方法回调函数抛出错误时, 错误信息应该在下一个then方法失败回调中能接收到
class MyPromise {
constructor(){
}
...
then(successCallback, failCallback) {
//promise2是我们当前then执行之后要返回的promise对象
const promise2 = new MyPromise((resolve, reject) => {
if(this.status == FULFILLED){ //当前promise对象状态是成功的
setTimeout(() => {
try{ //没有遇到错误就正常运行
let x = successCallback(this.value)
resolvePromise(promise2,x, resolve, reject)
}catch (err){
//then方法回调函数中抛出错误,直接调用返回的promise的reject方法。以执行下一个promise的失败回调
reject(err)
}
}, 0)
}
.....
})
return promise2
}
}
}
到目前为止,都只处理了 当前promise对象是成功的情况, 当前promise是失败的情况和当前promise是等待的状况 还没有写, 下面补一下:
当前promise是失败
class MyPromise {
constructor(){
}
...
then(successCallback, failCallback) {
//promise2是我们当前then执行之后要返回的promise对象
const promise2 = new MyPromise((resolve, reject) => {
if(this.status == FULFILLED){ //当前promise对象状态是成功的
...
}else if(this.status == REJECTED){ //当前promise状态是失败
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2,x, resolve, reject)
}catch(err) {
reject(err)
}
}, 0)
}else{
...
}
.....
})
return promise2
}
}
}
当前promise是异步进行的
class MyPromise{
constructor(executor){
...
}
...
then(successCallback, failCallback) {
//promise2是我们要返回的promise对象
const promise2 = new MyPromise((resolve, reject) => {
//判断状态
if(this.status == FULFILLED){
...
}else if(this.status == REJECTED){
...
}else{ //状态为等待,处理异步逻辑
//向成功回调中push一个匿名函数
this.successCallback.push(() => {
setTimeout(() => {
try {
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
}catch(err){
reject(err)
}
}, 0)
})
//向失败回调中push 匿名函数
this.failCallback.push(() => {
setTimeout(() => {
try {
let x = failCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
}catch (err) {
reject(err)
}
},0)
})
}
})
return promise2
}
}
当前promise异步执行到resolve或reject调用时:
resolve = (value) => {
if(this.status !== PENDING) return
this.status = FULFILLED
//保存成功之后的值
this.value = value
while(this.successCallback.length){
//不再需要参数了,因为resolve将value赋值给this.value, 而successCallback中的每一项需要this.value作为参数,直接用即可
this.successCallback.shift()()
}
}
reject = (reason) => {
if(this.status !== PENDING) return
this.status = REJECTED
// 保存失败的原因
this.reason = reason
while(this.failCallback.length){
//同resolve 不再需要参数
this.failCallback.shift()()
}
}
测试一下:
new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
}).then(res => {
console.log(res)
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('链式调用成功')
}, 1000)
})
}).then(res => {
console.log(res)
})
不出意外的话, 上面的代码会在2s后输出 成功, 1S后输出 链式调用成功
执行看下结果👇🏻
then方法回调函数变为可选参数
问题分析
1、 原生promise中
在原生的promise中,可以这样写:
const promise = new Promise((resolve, reject) => {
resolve(123)
})
promise.then().then().then().then(res => console.log(res))
我们在进行then方法的链式调用时,可以不传递回调函数, promise的状态会一直向后传递给有回调函数的then方法,进而得到promise的执行结果👇🏻
\
2、我们写的MyPromise中进行同样的操作:
const promise = new MyPromise((resolve, reject) => {
resolve(123)
})
promise.then().then().then().then(res => console.log(res))
可以看到,什么都没有输出:
说明我们的状态并没有传递给后面的then方法,先将then方法的调用方式改成这样:
const promise = new MyPromise((resolve, reject) => {
resolve(123)
})
promise
.then((res) => res)
.then((res) => res)
.then((res) => res)
.then((res) => console.log(res));
再次执行
我们通过手动在then方法中,将得到的结果, 传递给下一个then的方式,实现了和原生一样的效果,接下来试着把这一操作放入 MyPromise类中
修改代码
class MyPromise{
...
then(successCallback, failCallback){
//判断是否传入成功失败回调,如果没传就为其赋默认值
// 对于成功回调,直接将得到的结果返回
// 对于失败回调,抛出错误原因
successCallback = successCallback ? successCallback : value => value
failCallback = failCallback ? failCallback : reason => {throw reason}
...
}
}
如果调用then方法没有传入相应的成功失败回调函数, 我们就在MyPromise类中为其赋予默认值,将结果传递给下一个then方法
静态方法 resolve 和 reject的实现
在原生的promise中,我们可以直接调用Promise类的resolve和reject方法去生成promise对象
像这样👇🏻
原生Promise 静态方法生成状态是成功的promise对象
Promise.resolve(123)
.then(res => {
console.log(res)
})
// 123
原生Promise 静态方法生产状态是失败的promise对象
Promise.reject(new Error('失败了'))
.then(null, reason => console.log(reason.message))
// 失败了
下面用我们的MyPromise来模拟实现一下, 因为resolve和reject方法是有Promise类去调用的,所以他们一定都是静态方法, 且他们的调用结果都会返回promise
用MyPromise实现私有方法 resolve和reject
class MyPromise{
...
static resolve(value){
//如果value是promise对象,直接返回
if(value instanceof MyPromise) return value
//如果value是普通值,返回一个状态是成功的promise对象
return new MyPromise(resolve => resolve(value))
}
static reject(reason){
//这里一定是返回一个失败的promise对象
return new MyPromise((resolve, reject) => reject(reason))
}
}
测试一下代码:
//resolve普通值
MyPromise.resolve(123)
.then(res => console.log(res))
//resolvepromise对象
let p = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve(2000)
}, 2000)
})
MyPromise.resolve(p)
.then(res => {
console.log(res)
})
//reject
MyPromise.reject(new Error('MyPromise失败'))
.then(null, reason => console.log(reason.message))
输出结果:
先后输出
123
MyPromise失败
2s以后输出
2000
完整代码
到这里,我们手写promise基本完工了,贴下完整代码,以及自己的总结
const PENDING = 'pending',
FULFILLED = 'fiulfilled',
REJECTED = 'rejected'
// promise是一个类,创建时会传入一个函数,这个函数会立即执行
class Promise2{
constructor(executor){
//当promise内部运行出错时,直接调用this.reject
try{
executor(this.resolve, this.reject)
}catch(err) {
this.reject(err)
}
}
status = PENDING
value = undefined
reason = undefined
//保存多次调用then方法传入的成功和失败回调函数
successCallback = []
failCallback = []
resolve = (value) => {
//改变promise状态为成功
if(this.status !== PENDING) return
this.status = FULFILLED
//保存成功的结果
this.value = value
//先进先出的方式执行多次调用then方法传入的回调函数
while(this.successCallback.length){
this.successCallback.shift()()
}
}
reject = (reason) => {
//改变promise状态为失败
if(this.status !== PENDING) return
this.status = REJECTED
//保存失败原因
this.reason = reason
while(this.failCallback.length){
this.failCallback.shift()()
}
}
//then方法接收成功和失败回调函数
//then方法要做的第一件事是去判断当前promise是成功的还是失败的
then(successCallback, failCallback){
//将then方法中的成功失败回调变为可选参数
successCallback = successCallback ? successCallback : val => val
failCallback = failCallback ? failCallback : reason => {throw reason}
//实现then方法的链式调用,首先then方法应该返回一个promise对象
const p2 = new Promise2((resolve, reject) => {
if(this.status == FULFILLED){ //调用then方法时当前状态是成功
setTimeout(()=> {
//错误捕获, 当运行出现错误时, 直接调用返回的promise对象的reject方法
try{
let x = successCallback(this.value)
resolvePromise(p2, x, resolve, reject)
}catch(err){
reject(err)
}
}, 0)
}else if(this.status == REJECTED){ //调用then方法时当前状态是失败
setTimeout(() => {
try{
let x = failCallback(this.reason)
resolvePromise(p2, x, resolve, reject)
}catch(err){
reject(err)
}
}, 0)
}else{ //处理异步操作
//此时并不知道当前promise是成功还是失败,将传入的处理函数都保存起来,等到调用resolve或reject是再去决定使用哪个回调
this.successCallback.push(() => {
setTimeout(()=> {
try{
let x = successCallback(this.value)
resolvePromise(p2, x, resolve, reject)
}catch(err){
reject(err)
}
}, 0)
})
this.failCallback.push(()=> {
setTimeout(() => {
try{
let x = failCallback(this.reason)
resolvePromise(p2, x, resolve, reject)
}catch(err){
reject(err)
}
}, 0)
})
}
})
return p2
}
}
function resolvePromise(p2, x, resolve, reject){
//如果返回的promise对象与和上一个.then执行后返回的promise是一样的,直接调用reject方法
if(p2 === x) {
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof Promise2){ //x是promise对象
//调用x的then方法去查看x的状态, 并传入成功和失败回调函数
//如果返回的promise对象是同步的, 使用resolve 和 reject将参数传递给下一个.then使用
//如果返回的promise对象是异步的,就将 此时的resolve和reject 传入异步的successCallback和failCallback中,等返回的promise有了执行结果后,去调用相应的回调函数,下一个.then就可以获取到值
x.then(val => resolve(val), reason => reject(reason))
}else{ //x是普通值
resolve(x)
}
}
module.exports = Promise2
总结
1、then方法的作用首先是 查看当前promise状态!!!
然后再根据状态去确定要什么
2、在支持链式调用时,then方法查到当前promise是等待状态时,放入的内容理解:
then方法查到当前当前promise是成功时,会进行以下操作:
就是圈出来的代码块一中的内容, 也就是代码块一中的内容就是成功回调函数要做的事情。因此当前promise状态是等待时,我们只要创建一个匿名函数,将代码块中的内容放入匿名函数, 最后将匿名函数push进successCallback就可以了
3、圈出的地方异步执行的原因
在这里我们要比较 p2 和x是不是同一个promise对象,而只有new Promise2()执行完之后,才能拿到p2, 因此这里要等同步代码执行完之后再去执行, 所以将其变成异步