我们知道,JS是单线程,一次只能执行一个任务,如果有多个任务就要排队,一个任务完成以后继续下一个任务,但是发送请求获取数据是需要时间的,因此异步编程就成了一个热点,使用异步可以使得js在等待的这段时间去做其他的事情,传统的异步操作是通过【回调函数和事件】。
但是回调函数有一个致命的缺点,==就是很容易陷入回调地狱,这会造成代码层次复杂可读性差难以维护的问题==。因此ES6原生提供Promise对象统一了江湖上的一些解决方法,将其列入规范,使得异步的操作「近乎」同步化。
1.Promise的含义
所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。
Promise对象有以下两个特点。
(1)==对象的状态不受外界影响==。Promise对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)==一旦状态改变,就不会再变,任何时候都可以得到这个结果==。Promise对象的状态改变,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。此外,Promise对象提供统一的接口,使得控制异步操作更加容易。
2.基本用法
ES6 规定,Promise对象是一个构造函数,用来生成Promise实例
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去,==可以用then方法分别指定resolved状态和rejected状态的回调函数。==
promise.then(function(value) {
// success
}, function(error) {
// failure
});
reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
3.链式调用
3.1 then
Promise 实例具有then方法,也就是说,then方法是定义在原型对象Promise.prototype上的。它的作用是为 Promise 实例添加状态改变时的回调函数。前面说过,then方法的第一个参数是resolved状态的回调函数,第二个参数是rejected状态的回调函数,它们都是可选的。
直接看拓展后的代码,再去推导then的作用
var p = Promise.resolve( 21 );
p.then(function(v){
console.log(v);
// 创建一个promise并返回
return new Promise( function(resolve,reject){
// 引入异步!
setTimeout( function(){
// 用值42填充
resolve( v * 2 );
}, 100 );
});
})
.then(function(v){
console.log( v );
});
v 的第一个log值 21 ;第二个log值 42
==说明第二个then是在前一步中的100ms延迟之后运行的==
这种强大实在不可思议!在这些例子中,一步步传递的值是可选的。如果不显式返回一个值,就会隐式返回 undefined,并且这些 promise 仍然会以同样的方式链接在一起。这样,每个 Promise 的决议就成了继续下一个步骤的信号。
通俗一点来说
- Promise对象的then方法返回的是一个新的Promise对象。
- 后面的then方法就是在为上一个then返回的Promise注册回调。
- 前面then方法中回调函数的返回值会作为后面then方法回调的参数。
- 如果回调中返回的是Promise,那后面then方法的回调会等待它的结束。
3.2. 错误处理catch
const promise = new Promise(function(resolve, reject) {
throw new Error('test');
});
promise.catch(function(error) {
console.log(error);
});
// Error: test
如果 Promise 状态已经变成resolved,再抛出错误是无效的。
const promise = new Promise(function(resolve, reject) {
resolve('ok');
throw new Error('test');
});
promise
.then(function(value) { console.log(value) })
.catch(function(error) { console.log(error) });
// ok
还是那个道理,==因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。==
catch()方法返回的还是一个 Promise 对象,因此后面还可以接着调用then()方法。
const someAsyncThing = function() {
return new Promise(function(resolve, reject) {
// 下面一行会报错,因为x没有声明
resolve(x + 2);
});
};
someAsyncThing()
.catch(function(error) {
console.log('oh no', error);
})
.then(function() {
console.log('carry on');
});
// oh no [ReferenceError: x is not defined]
// carry on
上面代码运行完catch()方法指定的回调函数,会接着运行后面那个then()方法指定的回调函数。如果没有报错,则会跳过catch()方法。
3.3 Promise.prototype.finally()
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
上面代码中,不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
finally方法的回调函数不接受任何参数,这意味着没有办法知道,前面的 Promise 状态到底是fulfilled还是rejected。这表明,finally方法里面的操作,应该是与状态无关的,不依赖于 Promise 的执行结果。
4.相关API
4.1 Promise.all()
Promise.all()方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
Promise.all 等待所有都完成(==或第一个失败==)。
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
- 如果参数中包含非 promise 值,这些值将被忽略,但仍然会被放在返回数组中(如果 promise 完成的话):
- Promise.all 在任意一个传入的 promise 失败时返回失败。例如,如果你传入的 promise中,有四个 promise 在一定的时间之后调用成功函数,==有一个立即调用失败函数,那么 Promise.all 将立即变为失败==。
4.2 Promise.race()
Promise.race方法同样是将多个Promise实例,包装成一个新的Promise实例。可以传递多个Promise对象作为参数,如果实例红有一个实例率先改变状态,那么race的状态就会跟着改变。
const promise1 = new Promise((resolve, reject) => {
reject();
})
const promise2 = new Promise((resolve, reject) => {
resolve();
})
const promise3 = new Promise((resolve, reject) => {
reject();
})
const promiseRace = Promise.race([promise1, promise2, promise3]).then(res => {
console.log('race then');
}).catch(error => {
console.log('race catch');
})
// race catch
有时候,我们希望等到一组异步操作都结束了,不管每一个操作是成功还是失败,再进行下一步操作。但是,现有的 Promise 方法很难实现这个要求。
4.3 Promise.allSettled()
可能会先想到Promise.all(),但是Promise.all()方法只适合所有异步操作都成功的情况,如果有一个操作失败,就无法满足要求。
const resolved = Promise.resolve(42);
const rejected = Promise.reject(-1);
const allSettledPromise = Promise.allSettled([resolved, rejected]);
allSettledPromise.then(function (results) {
console.log(results);
});
// [
// { status: 'fulfilled', value: 42 },
// { status: 'rejected', reason: -1 }
// ]
4.4 Promise.any()
只要参数实例有一个变成fulfilled状态,包装实例就会变成fulfilled状态;如果所有参数实例都变成rejected状态,包装实例就会变成rejected状态。
Promise.any()跟Promise.race()方法很像,只有一点不同,就是Promise.any()不会因为某个 Promise 变成rejected状态而结束,必须等到所有参数 Promise 变成rejected状态才会结束。
var resolved = Promise.resolve(42);
var rejected = Promise.reject(-1);
var alsoRejected = Promise.reject(Infinity);
Promise.any([resolved, rejected, alsoRejected]).then(function (result) {
console.log(result); // 42
});
Promise.any([rejected, alsoRejected]).catch(function (results) {
console.log(results); // [-1, Infinity]
});
4.5 Promise.resolve() 和 Promise.reject()
创建一个已被拒绝的 Promise 的快捷方式是使用 Promise.reject(..),所以以下两个 promise 是等价的:
var p1 = new Promise( function(resolve,reject){
reject( "Oops" );
} );
var p2 = Promise.reject( "Oops" );
Promise.resolve()方法的参数分成四种情况。
(1)参数是一个 Promise 实例
如果参数是 Promise 实例,那么Promise.resolve将不做任何修改、原封不动地返回这个实例。
(2)参数是一个thenable对象
thenable对象指的是具有then方法的对象,比如下面这个对象。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
Promise.resolve()方法会将这个对象转为 Promise 对象,然后就立即执行thenable对象的then()方法。
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function (value) {
console.log(value); // 42
});
上面代码中,thenable对象的then()方法执行后,对象p1的状态就变为resolved,从而立即执行最后那个then()方法指定的回调函数,输出42。
(3)参数不是具有then()方法的对象,或根本就不是对象
如果参数是一个原始值,或者是一个不具有then()方法的对象,则Promise.resolve()方法返回一个新的 Promise 对象,状态为resolved。
const p = Promise.resolve('Hello');
p.then(function (s) {
console.log(s)
});
// Hello
上面代码生成一个新的 Promise 对象的实例p。由于字符串Hello不属于异步操作(判断方法是字符串对象不具有 then 方法),返回 Promise 实例的状态从一生成就是resolved,所以回调函数会立即执行。Promise.resolve()方法的参数,会同时传给回调函数。
(4)不带有任何参数
Promise.resolve()方法允许调用时不带参数,直接返回一个resolved状态的 Promise 对象。
所以,如果希望得到一个 Promise 对象,比较方便的方法就是直接调用Promise.resolve()方法。
const p = Promise.resolve();
p.then(function () {
// ...
});
上面代码的变量p就是一个 Promise 对象。
5.小试牛刀
题目一
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('once')
resolve('success')
}, 1000)
})
promise.then((res) => {
console.log(res)
})
promise.then((res) => {
console.log(res)
})
promise的构造函数只会执行一次,而then方法可以多次调用,但是第二次是直接返回结果,不会有异步等待的时间,所以执行结果是: 过一秒打印:once,success,success。
题目二
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
reject('error');
})
promise.then(() => {
console.log(3);
}).catch(e => console.log(e))
console.log(4);
解析:规则一,promise构造函数的代码会立即执行,then或者reject里面的代码会放入异步微任务队列,在宏任务结束后会立即执行。规则二:promise的状态一旦变更为成功或者失败,则不会再次改变,所以执行结果为:1,2,4,3。而catch里面的函数不会再执行。
6.手写Promise
下面代码是Promise基本用法的代码实现
1、Promise 的声明
首先呢,promise肯定是一个类,我们就用class来声明。 • 由于 new Promise((resolve, reject)=>{}) ,所以传入一个参数(函数),秘籍里叫他executor,传入就执行。 •executor里面有两个参数,一个叫resolve(成功),一个叫reject(失败)。 •由于resolve和reject可执行,所以都是函数,我们用let声明。
class Promise{
// 构造器
constructor(executor){
// 成功
let resolve = () => { };
// 失败
let reject = () => { };
// 立即执行
executor(resolve, reject);
}
}
2、解决基本状态
秘籍对Promise有规定:
•Promise存在三个状态(state)pending、fulfilled、rejected
•pending(等待态)为初始态,并可以转化为fulfilled(成功态)和rejected(失败态)
•成功时,不可转为其他状态,且必须有一个不可改变的值(value)
•失败时,不可转为其他状态,且必须有一个不可改变的原因(reason)
• new Promise((resolve, reject)=>{resolve(value)}) resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变。
• new Promise((resolve, reject)=>{reject(reason)}) reject为失败,接收参数reason,状态改变为rejected,不可再次改变。
•若是executor函数报错 直接执行reject();
于是乎,我们获得以下代码:
class Promise{
static PENDING = '待定'
static FULFILLED = '成功'
static REJECTED = '拒绝'
constructor(executor){
this.Status = Commitment.PENDING
this.Result = null
this.ResloveCallBacks = []
this.RejectCallBacks = []
let resolve = value => {
// state改变,resolve调用就会失败
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.FULFILLED
this.Result = value
}
};
let reject = reason => {
// state改变,reject调用就会失败
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.REJECTED
this.Result = value
}
};
// 如果executor执行报错,直接执行reject
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
3、then方法
秘籍规定:Promise有一个叫做then的方法,里面有两个参数:onFulfilled,onRejected,成功有成功的值,失败有失败的原因
- 当状态state为fulfilled,则执行onFulfilled,传入this.value。当状态state为rejected,则执行onRejected,传入this.value
- onFulfilled,onRejected如果他们是函数,则必须分别在fulfilled,rejected后被调用,value或reason依次作为他们的第一个参数
class Promise{
constructor(executor){...}
// then 方法 有两个参数onFulfilled onRejected
then(onFulfilled,onRejected) {
// 状态为fulfilled,执行onFulfilled,传入成功的值
if (this.Status === Commitment.FULFILLED) {
onFulfilled(this.Result);
};
// 状态为rejected,执行onRejected,传入失败的原因
if (this.Status === Commitment.REJECTED) {
onRejected(this.Result);
};
}
}
4、解决异步实现
现在基本可以实现简单的同步代码,但是当resolve在setTomeout内执行,then时state还是pending等待状态 我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们 类似于发布订阅,先将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。
class Promise{
constructor(executor){
this.Status = Commitment.PENDING
this.Result = null
this.ResloveCallBacks = []
this.RejectCallBacks = []
let resolve = value => {
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.FULFILLED
this.Result = value
this.ResloveCallBacks.forEach(callback => {
callback(value)
})
}
};
let reject = value => {
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.REJECTED
this.Result = value
this.RejectCallBacks.forEach(callback => {
callback(value)
})
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
if (this.Status === Commitment.FULFILLED) {
onFulfilled(this.value);
};
if (this.Status === Commitment.REJECTED) {
onRejected(this.reason);
};
if (this.Status === Commitment.PENDING) {
// onFulfilled传入到成功数组
this.ResloveCallBacks.push(()=>{
onFulfilled(this.Result);
})
// onRejected传入到失败数组
this.RejectCallBacks.push(()=>{
onRejected(this.Result);
})
}
}
}
5、解决链式调用
我门常常用到 new Promise().then().then() ,这就是链式调用,用来解决回调地狱
1、为了达成链式,我们默认在第一个then里返回一个promise。秘籍规定了一种方法,就是在then里面返回一个新的promise,称为promise2: promise2 = new Promise((resolve, reject)=>{}) •将这个promise2返回的值传递到下一个then中 •如果返回一个普通的值,则将普通的值传递给下一个then中
2、当我们在第一个then中 return 了一个参数(参数未知,需判断)。这个return出来的新的promise就是onFulfilled()或onRejected()的值
秘籍则规定onFulfilled()或onRejected()的值,即第一个then返回的值,叫做x,判断x的函数叫做resolvePromise
class Promise{
constructor(executor){
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
let resolve = value => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
};
let reject = reason => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// 声明返回的promise2
let promise2 = new Promise((resolve, reject)=>{
if (this.Status === Commitment.FULFILLED) {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
};
if (this.Status === Commitment.REJECTED) {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
};
if (this.Status === Commitment.PENDING) {
this.ResloveCallBacks.push(()=>{
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
})
this.RejectCallBacks.push(()=>{
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
})
}
});
// 返回promise,完成链式
return promise2;
}
}
6、完成resolvePromise函数
秘籍规定了一段代码,让不同的promise代码互相套用,叫做resolvePromise
- 如果 x === promise2,则是会造成循环引用,自己等待自己完成,则报“循环引用”错误
let p = new Promise(resolve => {
resolve(0);
});
var p2 = p.then(data => {
// 循环引用,自己等待自己完成,一辈子完不成
return p2;
})
1、判断x
- Otherwise, if x is an object or function,Let then be x.then
- x 不能是null
- x 是普通值 直接resolve(x)
- x 是对象或者函数(包括promise), let then = x.then 2、当x是对象或者函数(默认promise)
- 声明了then
- 如果取then报错,则走reject()
- 如果then是个函数,则用call执行then,第一个参数是this,后面是成功的回调和失败的回调
- 如果成功的回调还是pormise,就递归继续解析 3、成功和失败只能调用一个 所以设定一个called来防止多次调用
const resolvePromise = (promise2, x, resolve, reject) => {
// x和promise2不能是同一个值,如果是同一个值就报错
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<promise>')
)
}
// 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
if (typeof x === 'object' && x != null || typeof x === 'function') {
try {
let then = x.then // 取then可以报错,报错就走reject()
if (typeof then === 'function') {
// 用then.call()为了避免在使用一次x.then报错
then.call(x, y => {
console.log('y', y)
//递归调用
resolvePromise(x, y, resolve, reject)// 采用promise的成功结果,并且向下传递
}, r => {
reject(r)// 采用promise的失败结果,并且向下传递
})
} else {
resolve(x)// x不是一个函数,是一个对象
}
} catch (err) {
reject(err)
}
} else {
// x是一个普通值
resolve(x)
}
}
7、解决其他问题
1、秘籍规定onFulfilled,onRejected都是可选参数,如果他们不是函数,必须被忽略
- onFulfilled返回一个普通的值,成功时直接等于 value => value
- onRejected返回一个普通的值,失败时如果直接等于 value => value,则会跑到下一个then中的onFulfilled中,所以直接扔出一个错误 reason => throw err 2、秘籍规定onFulfilled或onRejected不能同步被调用,必须异步调用。我们就用setTimeout解决异步问题
- 如果onFulfilled或onRejected报错,则直接返回reject()
class Promise{
constructor(executor){
this.Status = Commitment.PENDING
this.Result = null
this.ResloveCallBacks = []
this.RejectCallBacks = []
let resolve = value => {
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.FULFILLED
this.Result = value
this.ResloveCallBacks.forEach(callback => {
callback(value)
})
}
};
let reject = reason => {
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.REJECTED
this.Result = value
this.RejectCallBacks.forEach(callback => {
callback(value)
})
}
};
try{
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
then(onFulfilled,onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.Status === Commitment.FULFILLED) {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.Status === Commitment.REJECTED) {
// 异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.Status === Commitment.PENDING) {
this.ResloveCallBacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.RejectCallBacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise,完成链式
return promise2;
}
}
下面是完整的Promise实现代码
class Commitment {
static PENDING = '待定'
static FULFILLED = '成功'
static REJECTED = '拒绝'
constructor(executor) {
this.Status = Commitment.PENDING
this.Result = null
this.ResloveCallBacks = []
this.RejectCallBacks = []
let resolve = value => {
//resolve和reject是在时间循环末尾执行的 加setTimeout
setTimeout(() => {
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.FULFILLED
this.Result = value
this.ResloveCallBacks.forEach(callback => {
callback(value)
})
}
});
}
let reject = value => {
setTimeout(() => {
if (this.Status === Commitment.PENDING) {
this.Status = Commitment.REJECTED
this.Result = value
this.RejectCallBacks.forEach(callback => {
callback(value)
})
}
});
}
try {
executor(resolve, reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
// onFulfilled如果不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected如果不是函数,就忽略onRejected,直接扔出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
let promise2 = new Promise((resolve, reject) => {
if (this.Status === Commitment.FULFILLED) {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
if (this.Status === Commitment.REJECTED) {
// 异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
};
// 当resolve在setTomeout内执行,then时state还是pending等待状态 我们就需要在then调用的时候,将成功和失败存到各自的数组,一旦reject或者resolve,就调用它们
// 类似于发布订阅,先将then里面的两个函数储存起来,由于一个promise可以有多个then,所以存在同一个数组内。
if (this.Status === Commitment.PENDING) {
this.ResloveCallBacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.RejectCallBacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.Result);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0)
});
};
});
// 返回promise,完成链式
return promise2;
}
}
const resolvePromise = (promise2, x, resolve, reject) => {
// x和promise2不能是同一个人,如果是同一个人就报错
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<promise>')
)
}
// 判断如果x是否是一个对象,判断函数是否是对象的方法有:typeof instanceof constructor toString
if (typeof x === 'object' && x != null || typeof x === 'function') {
try {
let then = x.then // 取then可以报错,报错就走reject()
if (typeof then === 'function') {
// 用then.call()为了避免在使用一次x.then报错
then.call(x, y => {
console.log('y', y)
//递归调用
resolvePromise(x, y, resolve, reject)// 采用promise的成功结果,并且向下传递
}, r => {
reject(r)// 采用promise的失败结果,并且向下传递
})
} else {
resolve(x)// x不是一个函数,是一个对象
}
} catch (err) {
reject(err)
}
} else {
// x是一个普通值
resolve(x)
}
}
大家可以跟着 史上最最最详细的手写Promise教程 这篇文章,按步骤手写一边Promise,更加方便与记忆和理解。