githubjavascript
博客java
Promise
的声明当咱们使用Promise
的时候,一般都是new Promise((resolve, reject) => {})
。git
所以咱们能够看出:github
Promise
是一个类;Promise
类的构造函数的第一个参数是函数,这个函数叫处理器函数(executor function
);resolve
和reject
resolve
函数;reject
函数。所以,咱们能够初步声明一下Promise
类。shell
class Promise {
/** * 构造器 * @returns {Promise<object>} * @param executor<function>: executor有两个参数:resolve和reject */
constructor(executor) {
// resolve 成功
const resolve = () => {};
// reject 失败
const reject = () => {};
// 执行 executor
executor(resolve,reject);
}
}
复制代码
Promise
存在着三种状态:pending
(等待态)、fulfilled
(成功态)和rejected
(失败态):数组
Promise
的初始状态是pending
状态;pending
状态能够转换为fulfilled
状态和rejected
状态;fulfilled
状态不能够转为其余状态,且必须有一个不可改变的值(value);rejected
状态不能够转为其余状态,且必须有一个不可改变的缘由(reason);resolve
函数并传入参数value,则状态改变为fulfilled
,且不能够改变;reject
函数并传入参数reason,则状态改变为rejected
,且不能够改变;reject
函数。所以,咱们须要在Promise
类中设置三个变量:state
(状态变量),value
(成功值的变量)和reason
(失败缘由的变量),而后在resolve
函数、reject
函数以及执行executor
函数报错的时候改变state
的值。promise
class Promise {
constructor(executor) {
// 初始化状态
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的缘由
this.reason = undefined;
/** * resolve 成功函数 * @param value<any>: 成功的值 */
const resolve = (value) => {
// 只能在状态为pending的时候执行
if(this.state === 'pending'){
// resolve调用后,state转化为fulfilled
this.state = 'fulfilled';
// 存储value
this.value = value;
}
};
/** * reject 失败函数 * @param reason<any>: 失败的缘由 */
const reject = (reason) => {
// 只能在状态为pending的时候执行
if(this.state === 'pending'){
// resolve调用后,state转化为rejected
this.state = 'rejected';
// 存储reason
this.reason = reason;
}
};
// 若是executor执行报错,直接执行reject()
try {
executor(resolve,reject);
}catch (e){
reject(e);
}
}
}
复制代码
then
方法Promise
有一个then
方法,而该方法中有两个参数:onFulfilled
和onRejected
:markdown
fulfilled
,只执行onFulfilled
,传入this.value
;rejected
,只执行onRejected
,传入this.reason
;所以咱们能够来实现一下then
方法。异步
class Promise {
constructor(executor) {...}
/** * then 方法 * @param onFulfilled<function>: 状态为fulfilled时调用 * @param onRejected<function>: 状态为rejected时调用 */
then(onFulfilled, onRejected) {
// 状态为fulfilled的时候,执行onFulfilled,并传入this.value
if(this.state === 'fulfilled'){
/** * onFulfilled 方法 * @param value<function>: 成功的结果 */
onFulfilled(this.value)
}
// 状态为rejected的时候,onRejected,并传入this.reason
if(this.state === 'rejected'){
/** * onRejected 方法 * @param reason<function>: 失败的缘由 */
onRejected(this.reason)
}
}
}
复制代码
Promise
实际上一个异步操做:async
resolve()
是在setTimeout
内执行的;then()
函数时,若是状态是pending
时,咱们须要等待状态结束后,才继续执行,所以此时咱们须要将then()
的两个参数onFulfilled
和onRejected
存起来;Promise
实例能够调用屡次then()
,所以咱们须要将onFulfilled
和onRejected
各类用数组存起来。所以咱们能够借着完善代码:
class Promise {
/** * 构造器 * @returns {Promise<object>} * @param executor<function>: executor有两个参数:resolve和reject */
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
// 存储onFulfilled的数组
this.onResolvedCallbacks = [];
// 存储onRejected的数组
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
// 一旦resolve执行,调用onResolvedCallbacks数组的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦reject执行,调用onRejectedCallbacks数组的函数
this.onRejectedCallbacks.forEach(fn=>fn());
}
};
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.state === 'fulfilled') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
// 状态为pending的时候,将onFulfilled、onRejected存入数组
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
复制代码
咱们经常会像下面代码同样使用Promise
:
new Promise()
.then()
.then()
.then()
复制代码
这种方法叫作链式调用,一般是用来解决回调地狱(Callback Hell
)的,就以下的代码:
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err)
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename)
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err)
} else {
console.log(filename + ' : ' + values)
aspect = (values.width / values.height)
widths.forEach(function (width, widthIndex) {
height = Math.round(width / aspect)
console.log('resizing ' + filename + 'to ' + height + 'x' + height)
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function(err) {
if (err) console.log('Error writing file: ' + err)
})
}.bind(this))
}
})
})
}
})
复制代码
为了实现链式调用,咱们须要知足一下几点:
then()
返回一个新的Promise
实例;then()
返回了一个值,则这个值就是onFulfilled()
或者onRejected()
的值,咱们须要把这个值传递到下一个then()
中。而对于上一个then()
的返回值,咱们须要对齐进行必定的处理,所以封装一个resolvePromise()
的方法去进行判断处理;
接下来咱们对then()
方法进行修改:
class Promise {
constructor(executor) { ... }
/** * then 方法 * @returns {Promise<object>} * @param onFulfilled<function>: 状态为fulfilled时调用 * @param onRejected<function>: 状态为rejected时调用 */
then(onFulfilled, onRejected) {
// 返回一个新的Promise实例
const newPromise = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
const x = onFulfilled(this.value)
// 对返回值进行处理
resolvePromise(newPromise, x, resolve, reject);
}
if (this.state === 'rejected') {
const x = onRejected(this.reason);
// 对返回值进行处理
resolvePromise(x, resolve, reject);
}
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
const x = onFulfilled(this.value);
// 对返回值进行处理
resolvePromise(newPromise, x, resolve, reject);
})
this.onRejectedCallbacks.push(() => {
const x = onRejected(this.reason);
// 对返回值进行处理
resolvePromise(newPromise, x, resolve, reject);
})
}
});
return newPromise;
}
}
function resolvePromise() {}
复制代码
resolvePromise
函数对于上一个then()
的返回值,咱们用x
变量存起来,而后须要对它进行一个处理:
x
是否是Promise
实例;
Promise
实例,则取它的结果,做为新的Promise
实例成功的结果;Promise
成功的结果;而后咱们处理返回值后,须要利用newPromise
的resolve
和reject
方法将结果返回。
这里咱们还须要注意一个地方,就是x
等于newPromise
的话,这时会形成循环引用,致使死循环。
let p = new Promise(resolve => {
resolve(0);
});
const p2 = p.then(data => {
// 循环引用,本身等待本身完成,致使死循环
return p2;
})
复制代码
所以,resolvePromise
函数须要4个参数,即newPromise
,x
、resolve
和reject
。
因此咱们来实现一下resolvePromise
函数:
/** * resolvePromise 方法 * @param newPromise<object>: 新的Promise实例 * @param x<any>: 上一个then()的返回值 * @param resolve<function>:Promise实例的resolve方法 * @param reject<function>:Promise实例的reject方法 */
function resolvePromise(newPromise, x, resolve, reject) {
// 循环引用报错
if(x === newPromise){
// reject报错
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 防止屡次调用
let called;
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
let then = x.then;
// x 为Promise实例
if (typeof then === 'function') {
// 使用call执行then(),call的第一个参数是this,后续即then()的参数,即第二个是成功的回调方法,第三个为失败的回调函数
then.call(x, y => {
// 成功和失败只能调用一个
if(called)return;
called = true;
// resolve 的结果依旧是promise实例,那就继续解析
resolvePromise(newPromise, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if(called)return;
called = true;
// 失败了就直接返回reject报错
reject(err);
})
} else {
// x 为普通的对象或方法,直接返回
resolve(x);
}
} catch (e) {
if(called)return;
called = true;
reject(e);
}
} else {
// x 为普通的值,直接返回
resolve(x);
}
}
复制代码
onFulfilled
和onRejected
关于then()
的两个参数——onFulfilled
和onRejected
:
onFulfilled
不是一个函数,就将它直接替换成函数value => value
;onRejected
不是一个函数,就将它直接替换成函数err => {throw err}
;class Promise {
constructor(executor) { ... }
then(onFulfilled, onRejected) {
// onFulfilled若是不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected若是不是函数,就忽略onRejected,直接抛出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
...
}
}
复制代码
其次,onFulfilled
和onRejected
是不能同步被调用的,必须异步调用。所以咱们就用setTimeout
解决一步问题。
class Promise {
constructor(executor) { ... }
then(onFulfilled, onRejected) {
// onFulfilled若是不是函数,就忽略onFulfilled,直接返回value
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
// onRejected若是不是函数,就忽略onRejected,直接抛出错误
onRejected = typeof onRejected === 'function' ? onRejected : err => {
throw err
};
return new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步调用
setTimeout(() => {
try {
const x = onFulfilled(this.value)
resolvePromise(x, resolve, reject);
}catch (e){
reject(e)
}
})
}
if (this.state === 'rejected') {
// 异步调用
setTimeout(() => {
try{
const x = onRejected(this.reason);
resolvePromise(x, resolve, reject);
}catch (e){
reject(e)
}
})
}
if (this.state === 'pending') {
this.onResolvedCallbacks.push(() => {
// 异步调用
setTimeout(() => {
try {
const x = onFulfilled(this.value);
resolvePromise(x, resolve, reject);
}catch (e){
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
// 异步调用
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(x, resolve, reject);
}catch (e){
reject(e)
}
})
})
}
});
}
}
复制代码
Promise
的其余方法Promise.all()
Promise.all()
方法接收一个promise
的iterable
类型的输入,包括Array
、Map
、Set
。而后返回一个Promise
实例,该实例回调返回的结果是一个数组,包含输入全部promise
的回调结果。
但只要任何一个输入的promise
的reject
回调执行或者输入不合法的promise
,就会立马抛出错误。
/** * Promise.all 方法 * @returns {Promise<object>} * @param promises<iterable>: 一个promise的iterable类型输入 */
Promise.all = function (promises) {
let arr = [];
return new Promise((resolve, reject) => {
if (!promises.length) resolve([]);
// 遍历promises
for(const promise of promises) {
promise.then(res => {
arr.push(res);
if(arr.length === promises.length){
resolve(arr);
}
}, reject)
}
})
}
复制代码
Promise.allSettled()
Promise.allSettled()
其实跟Promise.all()
很像,一样是接收一个promise
的iterable
类型的输入,但返回的是一个给定的promise
已经完成后的promise
,并带有一个对象数组,每一个对象标识着对应的promise
结果。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];
Promise.allSettled(promises).
then((results) => console.log(results));
// > Array [Object { status: "fulfilled", value: 3 }, Object { status: "rejected", reason: "foo" }]
复制代码
实现:
/** * Promise.allSettled 方法 * @returns {Promise<object>} * @param promises<iterable>: 一个promise的iterable类型输入 */
Promise.allSettled = function (promises) {
let arr = [];
return new Promise((resolve, reject) => {
try {
const processData = (data) => {
arr.push(data);
if(arr.length === promises.length){
resolve(arr);
}
}
if (!promises.length) resolve([]);
// 遍历promises
for(const promise of promises) {
promise.then(res => {
processData({state:'fulfilled', value: res})
}, err => {
processData({state:'rejected', reason: err})
})
}
}catch (e){
reject(e)
}
})
}
复制代码
Promise.any()
Promise.any()
跟Promise.all()
和Promise.allSettled()同样,一样是接收一个
promise的
iterable类型的输入。但只要其中的一个
promise成功,就返回那个已经成功的
promise,但若是没有一个
promise成功,就返回一个失败的
promise`。
/** * Promise.any 方法 * @returns {Promise<object>} * @param promises<iterable>: 一个promise的iterable类型输入 */
Promise.any = function (promises) {
return new Promise((resolve, reject) => {
// 若是传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise
if (!promises.length) reject();
// 若是传入的参数不包含任何 promise,则返回一个 异步完成 (asynchronously resolved)的 Promise。
if (typeof promises[Symbol.iterator] !== 'function' ||
promises === null ||
typeof promises === 'string') {
resolve()
}
let i = 0;
// 遍历promises
for (const promise of promises) {
promise.then(res => {
i++;
resolve(res);
}, err => {
i++;
if (i === promises.length) {
reject(err);
}
})
}
})
}
复制代码
Promise.race()
Promise.race()
,一样是接收一个promise
的iterable
类型的输入。一旦迭代器中的某个promise
完成了,无论是成功仍是失败,就会返回这个promise
。
/** * Promise.race 方法 * @returns {Promise<object>} * @param promises<iterable>: 一个promise的iterable类型输入 */
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
for (const promise of promises) {
promise.then(resolve, reject)
}
})
}
复制代码
Promise.reject()
和Promise.resolve()
Promise.reject()
方法返回一个带有拒绝缘由的Promise
对象;Promise.resolve()
方法返回一个以定值解析后的Promise
对象。
/** * Promise.reject 方法 * @returns {Promise<object>} * @param val<any> */
Promise.reject = function (val) {
return new Promise(reject => reject(val))
}
/** * Promise.resolve 方法 * @returns {Promise<object>} * @param val<any> */
Promise.resolve = function (val) {
return new Promise(resolve => resolve(val))
}
复制代码
catch()
和finally()
catch()
方法是用来处理失败的状况,它传入一个处理函数,而后返回一个promise
实例。实际上它是then()
的语法糖,只接受rejected
态的数据。
finally()
是在promise
结束时,不管结果是fufilled
仍是rejected
,都会执行指定的回调函数。一样也返回一个promise
实例。
class Promise {
constructor(executor) { ... }
then(onFulfilled, onRejected) { ... }
/** * catch 方法 * @returns {Promise<object>} * @param callback<function>: 处理函数 */
catch(callback) {
return this.then(null, callback);
}
/** * finally 方法 * @returns {Promise<object>} * @param callback<function>: 处理函数 */
finally(callback) {
return this.then(res => {
return Promise.resolve(callback()).then(() => res)
}, err => {
return Promise.reject(callback()).then(() => {
throw err
})
})
}
}
复制代码
Promise/A+
规范: github.com/promises-ap…
Promise/A+
测试工具: github.com/promises-ap…
安装promises-aplus-tests
插件。
yarn add promises-aplus-tests
复制代码
在Promise.js
后面插入下列代码。
// 测试
Promise.defer = Promise.deferred = function () {
let dfd = {}
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
module.exports = Promise;
复制代码
而后输入命令行进行测试。
promises-aplus-tests Promise.js
复制代码
结果:
872 passing (18s)
复制代码