手动实现 Promise API
一、Promise 手写
- 原理:利用发布者订阅者模式 构造函数接收一个
executor
函数,并会在new Promise()
时立即执行该函数then
时收集依赖,将回调函数收集到 成功/失败队列executor
函数中调用resolve/reject
函数
resolve/reject
函数被调用时会通知触发队列中的回调
两种写法:
写法1:ES5
(function(window) {
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
function Promise(executor) {
this.state = PENDING;
this.data = null;
this.callbacks = [];
function resolve(value) {
// Promise的状态只能改一次,所以只有pending状态时候才能执行resolve和reject
// 当Promise的状态为resolved|rejected就不能再次改变状态了
if (this.state !== PENDING) {
return;
}
this.state = RESOLVED;
this.data = value;
if (this.callbacks.length > 0) {
setTimeout(() => {
this.callbacks.forEach(callbacksObj => {
callbacksObj.onResolved(value);
});
});
}
}
function reject(reason) {
// Promise的状态只能改一次,所以只有pending状态时候才能执行resolve和reject
// 当Promise的状态为resolved|rejected就不能再次改变状态了
if (this.state !== PENDING) {
return;
}
this.state = REJECTED;
this.data = reason;
if (this.callbacks.length > 0) {
setTimeout(() => {
this.callbacks.forEach(callbacksObj => {
callbacksObj.onRejected(reason);
});
});
}
}
try {
executor(resolve.bind(this), reject.bind(this));
} catch (e) {
// 执行器抛出异常,Promise状态为失败,调用reject
reject(e);
}
}
Promise.prototype = {
constructor: Promise,
then(onResolved, onRejected) {
// 指定默认的回调函数
// 如果用户没有指定onRejected | onResolved 我们需要把值|异常穿透下去
// 异常穿透的关键一步,内部会捕捉并返回一个状态失败的Promise
onRejected =
typeof onRejected === "function"
? onRejected
: reason => {
throw reason;
};
onResolved =
typeof onResolved === "function" ? onResolved : value => value;
// 1. then中的回调函数发生异常,then返回失败的Promise,reason为异常
// 2. then的回调函数运行,返回非Promise值,then返回成功的Promise,value为return的值
// 3. then的回调函数运行,返回Promise,则then返回该promise
const self = this;
return new Promise((resolve, reject) => {
function handle(callback) {
try {
const result = callback(self.data);
if (result instanceof Promise) {
// 第3种情况,得到返回的promise值|原因,并改变返回的promise状态
result.then(resolve, reject);
} else {
// 第2种情况
resolve(result);
}
} catch (e) {
// 第1种情况
reject(e);
}
}
if (self.state === PENDING) {
// Promise状态为pending,先把回调函数放到队列里
self.callbacks.push({
onResolved() {
handle(onResolved);
},
onRejected() {
handle(onRejected);
}
});
} else if (self.state === RESOLVED) {
// Promise状态为resolved,异步执行回调函数,并通过handle改变return的Promise
setTimeout(() => {
handle(onResolved);
});
} else {
// Promise状态为rejected,异步执行回调函数,并通过handle改变return的Promise
setTimeout(() => {
handle(onRejected);
});
}
});
},
catch(onRejected) {
// 第一个参数写null,内部会把value数据向下传递
return this.then(null, onRejected);
}
};
Promise.resolve = function(value) {
// value 可以是Promise,也可以是值
// Promise => 根据promise状态改变return的状态
// 值 => 成功的Promise
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
};
Promise.reject = function(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
};
Promise.all = function(iterable) {
return new Promise((resolve, reject) => {
const arr = new Array(iterable.length);
const counter = 0;
iterable.forEach((p, index) => {
// 如果iterable中有值不是promise,那么包装成promise
Promise.resolve(p).then(
value => {
// 执行onResolved几次,就成功几次
// 这里不能用value代替counter,因为所有的操作都是异步的,不能确定谁先完成,如果最后一个先完成就会出问题
arr[index] = value;
counter++;
counter === arr.length ? resolve(arr) : null;
},
reason => {
// 只要有一个失败,整个promise失败
reject(reason);
}
);
});
});
};
Promise.all = function(iterable) {
return new Promise((resolve, reject) => {
let arr = [];
iterable.forEach((p, index) => {
Promise.resolve(p).then(
value => {
arr[index] = value;
if (arr.length === iterable.length) {
resolve(arr);
}
},
reason => {
reject(reason);
}
);
});
});
};
Promise.race = function(iterable) {
return new Promise((resolve, reject) => {
iterable.forEach(p => {
// 如果iterable中有值不是promise,那么包装成promise
Promise.resolve(p).then(
value => {
// 先成功,先调用,后续的不再改变状态
resolve(value);
},
reason => {
// 先失败,先调用,后续的不再改变状态
reject(reason);
}
);
});
});
};
// 自定义工具方法
Promise.resolveDelay = function(value, time) {
/**
* 返回一个成功的Promise对象,它在指定时间后才能成功
*/
return new Promise((resolve, reject) => {
setTimeout(() => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
}, time);
});
};
Promise.rejectDelay = function(reason, time) {
/**
* 返回一个Promise对象,它在指定时间后才能确定失败
*/
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(reason);
}, time);
});
};
window.Promise = Promise;
})(window);
写法二:ES6 class
const PENDING = "pending";
const RESOLVED = "resolved";
const REJECTED = "rejected";
class Promise {
constructor(executor) {
this.state = PENDING;
this.data = null;
this.callbacks = [];
let resolve = value => {
if (this.state !== PENDING) {
return;
}
this.state = RESOLVED;
this.data = value;
if (this.callbacks.length) {
process.nextTick(() => {
this.callbacks.forEach(item => {
item.onResolved(this.data);
});
});
}
};
let reject = reason => {
if (this.state !== PENDING) {
return;
}
this.state = REJECTED;
this.data = reason;
if (this.callbacks.length) {
process.nextTick(() => {
this.callbacks.forEach(item => {
item.onRejected(this.data);
});
});
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onResolved, onRejected) {
onResolved = typeof onResolved === "function" ? onResolved : value => value;
onRejected =
typeof onRejected === "function"
? onRejected
: reason => {
throw reason;
};
return new Promise((resolve, reject) => {
let handle = callback => {
try {
const result = callback(this.data);
if (result instanceof Promise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (e) {
reject(e);
}
};
if (this.state === PENDING) {
this.callbacks.push({
onResolved() {
handle(onResolved);
},
onRejected() {
handle(onRejected);
}
});
} else if (this.state === RESOLVED) {
process.nextTick(() => {
handle(onResolved);
});
} else {
process.nextTick(() => {
handle(onRejected);
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
static resolve(value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(resolve, reject);
} else {
resolve(value);
}
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
if (reason instanceof Promise) {
reason.then(reject, reject);
} else {
reject(reason);
}
});
}
static all(iterable) {
return new Promise((resolve, reject) => {
const arr = [];
let counter = 0;
iterable.forEach((p, index) => {
Promise.resolve(p).then(
value => {
counter++;
arr[index] = value;
if (counter === iterable.length) {
resolve(arr);
}
},
reason => {
reject(reason);
}
);
});
});
}
}
module.exports = Promise;
二、Promise.all() 手写
Promise.all() API
的功能:Promise.all(iterable)
方法返回一个 Promise 实例,此实例在 iterable 参数内所有的promise
都完成(resolved)”或参数中不包含promise
时回调完成(resolve);如果参数中 promise 有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败promise
的结果。- 实现思路:首先需要将输入数组中的所有
Promise
对象均运行起来;在有Promise
对象resolve
后,判断是否所有对象均已resolve
,当所有Promise
均被resolve
后进行整体的resolve
;此外,当任何一个Promise
对象出现reject
后,直接reject
。
function myPromiseAll(promise) {
if (!Array.isArray(promise)) {
// PromiseAll的入参必须是数组
return reject(new TypeError("promise must be an array"));
}
let result = [];
let count = 0;
return new Promise((resolve, reject) => {
// 执行所有的 Promise 对象
promise.forEach(item => {
Promise.resolve(item)
.then(res => {
result.push(res);
count++;
if (count == promise.length) {
// 当所有 Promise 都 resolve 之后,统一 resolve
resolve(result);
}
})
.catch(err => {
// 只要有任何 Promise 出现 reject, Promise.newAll 就直接 reject
reject(err);
});
});
});
}
三、Promise.race() 手写
Promise.race()
API 的功能:Promise.race(iterable)
方法返回一个promise
,一旦迭代器中的某个promise
解决或拒绝,返回的promise
就会解决或拒绝。- 实现思路:
Promise.race()
实际上相当于一个竞速过程,第一给被resolve
或reject
的对象会被resolve
或reject
。因此,只需要将上面Promise.all
的代码进行些许的改动即可
function myPromiseRace(promise) {
return new Promise((resolve, reject) => {
// 执行所有的 Promise 对象
promise.forEach(item => {
Promise.resolve(item)
.then(res => {
// 出现第一个被 resolve 的直接 resolve
resolve(res);
})
.catch(err => {
// 出现第一个被 reject 的直接 reject
reject(err);
});
});
});
}
四、Promise.allSettled() 手写
-
Promise.allSettled() API
的功能:Promise.allSettled()
方法返回一个在所有给定的promise
已被决议或被拒绝后决议的promise
,并带有一个对象数组,每个对象表示对应的promise
结果。 -
实现思路:首先同样运行所有的
Promise
对象,与Promise.all
不同的是,在有Promise
被reject
之后,我们不会直接reject
,而是记录下该 reject 的值和对应的状态rejected
;同样地,当Promise
对象被resolve
时我们也不仅仅局限于记录值,同时也会记录状态fulfilled
。当所有的Promise
对象都已决(解决或拒绝)后,我们统一resolve
记录了值(value)已决状态(status)的数组。
function myPromiseAllSettled(promise) {
let result = [];
let count = 0;
return new Promise(resolve => {
// 执行所有的 Promise 对象
promise.forEach(item => {
Promise.resolve(item)
.then(res => {
// 当有 Promise 被 resolve 之后,记录 resolve 值和状态,已决 Promise 计数加一
result.push({ status: "fulfilled", value: res });
count++;
if (count == promise.length) {
// 全部 Promise 已决,resolve
resolve(result);
}
})
.catch(err => {
// 当有 Promise 被 reject 后,记录 reject 值和状态,并且已决的 Promise 计数加一
result.push({ status: "rejected", value: err });
count++;
if (count == promise.length) {
// 全部 Promise 已决,resolve
resolve(result);
}
});
});
});
}
转载于: https://blog.csdn.net/qq_42552393/article/details/117000022#comments_16549335