promise代码实现要点
1、Promise是一个类,在执行的时候需要传入可执行的函数,这个函数会立即执行,并且执行之后Promise的状态会从pending转变成fufilled(成功)或rejected(失败),并且这一过程是不可逆的。
实现的第一步大致如下:
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
// 实例化的时候会立即执行
constructor(executor) {
// 利用try catch来处理构造器可能发生的错误
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e);
}
}
status = PENDING
// 执行成功后返回的值
value = undefined
// 执行失败后返回的值
reason = undefined
resolve = (value) => {
// 如果状态不是等待状态,则不能往下执行
if(this.status !== PENDING) return
this.status = FULFILLED
this.value = value
this.successCallback && this.successCallback(this.value)
}
reject = (error) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = error
this.failCallback && this.failCallback(this.reason)
}
then (successcallback,failcallback) {
if(this.status === FULFILLED){
successcallback(this.value)
}
else if(this.status === REJECTED) {
failcallback(this.reason)
}
}
}
module.exports = MyPromise;
在另一个文件中调用这个类:
const MyPromise = require('./myPromise')
function p1() {
return new MyPromise((resolve,reject) => {
resolve('success')
}
let promise1 = p1()
此时promise1已经拿到p1内部的执行结果了,如果想要拿到执行结果的数据,可通过使用then方法,then方法根据状态去调用成功回调或者失败回调,我们在类中加入此方法:
then (successcallback,failcallback) {
if(this.status === FULFILLED){
successcallback(this.value)
}
else if(this.status === REJECTED) {
failcallback(this.reason)
}
}
promise1.then((data)=>{
console.log(data);
},error => {
console.log(error);
})
至此,一个无异步操作代码初步实现
在函数中加入异步操作
function p1() {
return new MyPromise((resolve,reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
}
let promise1 = p1()
promise1.then(data => {
})
然后是对then、resolve、reject方法做修改:
// 成功回调
successCallback = undefined;
// 失败回调
failCallback = undefined;
resolve = (value) => {
// 如果状态不是等待状态,则不能往下执行
if(this.status !== PENDING) return
this.status = FULFILLED
this.value = value
this.successCallback && this.successCallback(this.value)
}
reject = (error) => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = error
this.failCallback && this.failCallback(this.reason)
}
then (successcallback,failcallback) {
if(this.status === FULFILLED){
successcallback(this.value)
}
else if(this.status === REJECTED) {
failcallback(this.reason)
}
// 状态为pendding时
else {
// 保存回调函数
this.successCallback = successcallback
this.failCallback = failcallback
}
}
这样就初步实现异步操作了,但这仅仅是调用了一次then方法的情况,如果多次调用then方法的时候:
1、首先要把successCallback与failCallback定义为数组,这样它们就可以在状态为pendding时接收多个回调;
2、在resolve与reject两个函数中对这两个数组里边的回调函数进行调用
// 成功回调
successCallback = [];
// 失败回调
failCallback = [];
resolve = (value) => {
// 如果状态不是等待状态,则不能往下执行
if (this.status !== PENDING)
return
this.status = FULFILLED
this.value = value
while (this.successCallback.length) {
this.successCallback.shift()(value)
}
}
reject = (error) => {
if (this.status !== PENDING)
return
this.status = REJECTED
this.reason = error
while (this.failCallback.length) {
this.failCallback.shift()(error)
}
}
then(successcallback, failcallback) {
if (this.status === FULFILLED) {
successcallback(this.value)
} else if (this.status === REJECTED) {
failcallback(this.reason)
}
// 状态为pendding时
else {
this.successCallback.push(successcallback)
this.failCallback.push(failcallback)
}
}
链式使用then方法
我们在promise中链式使用then方法时,当前then执行的结果可以传递给下一个then方法中,而且这个执行的结果必须是一个promise对象
promise1.then(data => {
return 1000;
}).then(data => {
console.log(data) //这里将会打印上一个回调函数返回的结果
})
then方法中的修改:
then(successcallback, failcallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let res1 = successcallback(this.value);
resolve(res1);
} else if (this.status === REJECTED) {
let err1 = failcallback(this.reason)reject(err1);
}
// 状态为pendding时
else {
this.successCallback.push(successcallback)
this.failCallback.push(failcallback)
}
})
return promise2;
}
但以上没有对res1的类型做判断,它可能会具备两种情况,普通值或者promise对象,
1、如果是普通值直接调用resolve
2、如果是promise对象,查看promise对象返回的结果,再根据promise对象返回的结果决定调用resolve 还是调用reject
以上两个判断步骤在状态成功或者失败时都要执行一遍
//声明一个函数去判断执行结果的类型
function resolvePromise(res, resolve, reject) {
if (res instanceof MyPromise) {
// promise 对象
res.then(value => resolve(value), reason => reject(reason));
} else {
// 普通值
resolve(res);
}
}
then(successcallback, failcallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
let res1 = successcallback(this.value);
resolvePromise(res1, resolve, reject)
} else if (this.status === REJECTED) {
let err1 = failcallback(this.reason)
resolvePromise(err1, resolve, reject)
} // 状态为pendding时
else {
this.successCallback.push(successcallback)
this.failCallback.push(failcallback)
}
})
return promise2;
}
测试代码中:
function p1() {
return new MyPromise((resolve, reject) => {
resolve('success')
})
}
function p2() {
return new MyPromise(function (resolve, reject) {
resolve('p2')
})
}
let promise1 = p1();
promise1.then((data) => {
console.log(data); //success
return p2();
}).then(value => {
console.log(value);//p2
})
promise中当前执行执行的回调中是不能返回对象本身的,所以我们还要在then方法中加判断执行结果是否就是对象本身
then(successcallback, failcallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 这里用异步是因为要将promise2传到另一个函数中,所以要等promise2实例化完毕
setTimeout(() => {
let res1 = successcallback(this.value);
resolvePromise(promise2, res1, resolve, reject)
}, 0);
} else if (this.status === REJECTED) {
let err1 = failcallback(this.reason)resolvePromise(err1, resolve, reject)
} // 状态为pendding时
else {
this.successCallback.push(successcallback)this.failCallback.push(failcallback)
}
})
return promise2;
}
function resolvePromise(promise2, res, resolve, reject) {
if (promise2 === res) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (res instanceof MyPromise) {
// promise 对象
res.then(value => resolve(value), reason => reject(reason));
} else {
// 普通值
resolve(res);
}
}
此时then方法中核心部分基本完成,但还未对错误状态进行捕获处理
then(successcallback, failcallback) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 这里用异步是因为要将promise2传到另一个函数中,所以要等promise2实例化完毕
setTimeout(() => {
try {
let res1 = successcallback(this.value);
resolvePromise(promise2, res1, resolve, reject)
} catch (e) {
// 将捕获到的错误传给下一个promise的reject方法
reject(e)
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let err1 = failcallback(this.reason)
resolvePromise(promise2, err1, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
}
// 状态为pendding时
else { // 这里也要对回调函数的执行结果进行处理
this.successCallback.push(() => {
try {
let res = successcallback(this.value)
resolvePromise(promise2, res, resolve, reject)
} catch (e) {
reject(e)
}
})
this.failCallback.push(() => {
try {
let err = failcallback(this.reason)
resolvePromise(promise2, err, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2;
}
then方法中的回调函数可作为可选参数
此外当一个promise对象多次链式调用then方法时,前边调用then方法中没有传递参数,最后一个then方法中的形参是可以拿到上一个回调函数(then)的返回值,也就是说then方法的参数是可选值;而在then方法中要对传入的两个回调函数进行判断,如果传入的函数为空则要做其他处理:
//then方法中加入这两句代码去做判断
successcallback = successcallback ? successcallback : value => value;
failcallback = failcallback ? failcallback : error => { throw error }
测试代码中:
let promise1 = new MyPromise((resolve, reject) => {
resolve('success')
// reject("fail")});
promise1.then().then().then(data => {
console.log(25);
console.log(data);
}, err => {
console.log(err);
})
Promise.all的实现
all方法接收的是一个数组,这个数组里边可以包含普通值以及Promise的实例对象,在执行的时候等数组中所有的promise对象状态都变为fulfilled时,然后返回一个结果数组,但在执行的过程中如果有其中一个promise对象的状态变为失败状态,则会直接触发reject回调返回失败值
static all(array) {
// 结果返回数组
let result = []
let count = array.length;
return new MyPromise((resolve, reject) => {
if (!Array.isArray(array)) {
return reject(new Error("The args must be array type"))
}
function normalData(key, value) {
result[key] = value
count--;
if (count == 0) {
resolve(result)
}
}
// for循环中存在异步操作,要等待异步操作执行完拿到结果才能进行下一步的操作
for (let i = 0; i < array.length; i++) {
const current = array[i];
if (current instanceof MyPromise) {
current.then(value => normalData(i, value), error => reject(error))
} else {
// 普通值
normalData(i, array[i])
}
}
})
}
测试代码中:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
})
}
function p2() {
return new MyPromise((resolve, reject) => {
reject('p2')
})
}
MyPromise.all([1, 2, p1(), p2(), 44]).then(res => {
console.log(res);
}, err => {
console.log("22" + err);
})
Promise.resolve的实现
resolve方法实现的思路比较简单,接收到传入的参数后先去判断它是否为promise对象,如果是则直接返回,否则将在方法内部实例化一个Promise对象,并且在这个新实例化的对象中传入一个执行器去调用resolve方法,并返回这个对象。
static resolve(value) {
if (value instanceof MyPromise)
return value else {
return new MyPromise(resolve => resolve(value))
}
}
测试代码中:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000);
})
}
MyPromise.resolve(1000).then(res => {
console.log(res);
})
MyPromise.resolve(p1()).then(res => {
console.log(res);
})
Promise.finally的实现
finally方法的特点是无论当前的promise对象最终执行的结果是成功还是失败都会去执行此方法,并且能够链式调用then方法拿到当前Promise对象执行结果;
finally(callback) { return this.then((value) => { callback() return value; },(error) => { callback() throw error; }) }
测试代码中:
function p2() { return new MyPromise(function (resolve, reject) { resolve('p2 success') })}p2().finally(()=> { console.log("回调"); }).then(res => { console.log(res);})
这里代码是有个问题的,如果我们在finally里边的回调函数中返回一个promise对象,finally方法是需要等待这个promise对象执行完成,所以需要做:
1、判断回调函数返回的是普通值还是promise对象
2、无论是普通值(将其转换为promise对象)还是promise对象都要等待它执行完成,并且返回结果值
finally (callback) {
return this.then((value) => {
return MyPromise.resolve(callback()).then(value => value)
}, (error) => {
return MyPromise.resolve(callback()).then(error => {
throw error
})
})
}
测试代码中:
function p1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
// resolve('success')
reject("fail p1")
}, 2000);
})
}
function p2() {
return new MyPromise(function (resolve, reject) {
// resolve('p2 success')
reject("p2 fail")
})
}
p2().finally(() => {
console.log("回调");
return p1()
}).then(res => {
console.log(res);
}, err => {
console.log(err);
})
catch方法
此方法用于处理当前的promise对象最终状态为失败的情况,也就是在then中是可以不传递失败的回调,然后失败的回调就会被catch所捕获
catch (failCallback) {
return this.then(undefined, failCallback)
}
测试代码中:
function p2() {
return new MyPromise((resolve, reject) => {
resolve('p2 success')
// reject("p2 fail")
})
}
p2().catch(err => {
console.log(err);
}).then(res => {
console.log(res);
})
完整代码:
const PENDING = 'pending'; // 等待
const FULFILLED = 'fulfilled'; // 成功
const REJECTED = 'rejected'; // 失败
class MyPromise {
// 实例化的时候会立即执行
constructor(executor) {
// 利用try catch来处理构造器可能发生的错误
try {
executor(this.resolve, this.reject)
} catch (e) {
this.reject(e);
}
}
status = PENDING
// 执行成功后返回的值
value = undefined
// 执行失败后返回的值
reason = undefined
// 成功回调
successCallback = [];
// 失败回调
failCallback = [];
resolve = (value) => {
// 如果状态不是等待状态,则不能往下执行
if (this.status !== PENDING)
return
this.status = FULFILLED
this.value = value while (this.successCallback.length) {
this.successCallback.shift()()
}
}
reject = (error) => {
if (this.status !== PENDING)
return
this.status = REJECTED
this.reason = error while (this.failCallback.length) {
this.failCallback.shift()(error)
}
}
then(successcallback, failcallback) {
successcallback = successcallback ? successcallback : value => value;
failcallback = failcallback ? failcallback : error => {
throw error
}
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
// 这里用异步是因为要将promise2传到另一个函数中,所以要等promise2实例化完毕
setTimeout(() => {
try {
let res1 = successcallback(this.value);
resolvePromise(promise2, res1, resolve, reject)
} catch (e) {
// 将捕获到的错误传给下一个promise的reject方法
reject(e)
}
}, 0);
} else if (this.status === REJECTED) {
setTimeout(() => {
try {
let err1 = failcallback(this.reason)
resolvePromise(promise2, err1, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
}
// 状态为pendding时
else {
// 这里也要对回调函数的执行结果进行处理
this.successCallback.push(() => {
try {
let res = successcallback(this.value)
resolvePromise(promise2, res, resolve, reject)
} catch (e) {
reject(e)
}
})
this.failCallback.push(() => {
try {
let err = failcallback(this.reason)
resolvePromise(promise2, err, resolve, reject)
} catch (e) {
reject(e)
}
})
}
})
return promise2;
}
static all(array) {
// 结果返回数组
let result = []
let count = array.length;
return new MyPromise((resolve, reject) => {
if (!Array.isArray(array)) {
return reject(new Error("The args must be array type"))
}
function normalData(key, value) {
result[key] = value
count--;
if (count == 0) {
console.log("108" + " " + result);
resolve(result)
}
}
// for循环中存在异步操作,要等待异步操作执行完拿到结果才能进行下一步的操作
for (let i = 0; i < array.length; i++) {
const current = array[i];
if (current instanceof MyPromise) {
current.then(value => normalData(i, value), error => reject(error))
} else {
// 普通值
normalData(i, array[i])
}
}
})
}
static resolve(value) {
if (value instanceof MyPromise)
return value else {
return new MyPromise(resolve => resolve(value))
}
}
finally (callback) {
return this.then((value) => {
return MyPromise.resolve(callback()).then(value => value)
}, (error) => {
return MyPromise.resolve(callback()).then(error => {
throw error
})
})
}
catch (failCallback) {
return this.then(undefined, failCallback)
}
}
function resolvePromise(promise2, res, resolve, reject) {
if (promise2 === res) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if (res instanceof MyPromise) {
// promise 对象
res.then(value => resolve(value), reason => reject(reason));
// res.then(resolve, reject);
} else {
// 普通值
resolve(res);
}
}
module.exports = MyPromise;