Bootstrap

看了就会,手写 Promise 全部 API 教程,包括处于 TC39 第四阶段草案的 Promise.any()


在这里插入图片描述

前言

我们在上篇用了很大功夫实现了 Promise 的核心方法,并且通过了 Promises/A+ 官方872个测试用例测试,接下来实现这些静态方法已经是小菜一碟了,因为这些 API 全部是对前面的封装而已。

上篇文章在这里:手把手一行一行代码教你“手写Promise“,完美通过 Promises/A+ 官方872个测试用例

官方 Promise 还有很多API ,除了 then 方法以外还有 两个实例方法:

  • Promise.prototype.catch
  • Promise.prototype.finally

◾ 以及目前 Promise 规范的 六个静态方法

  • Promise.resolve
  • Promise.reject
  • Promise.all
  • Promise.allSettled
  • Promise.any
  • Promise.race

在这里插入图片描述

虽然这些都不在 Promise/A+ 规范里面,但是我们也来实现一下吧,加深理解。其实我们前面我们用了很大功夫实现了 Promise/A+ ,现在再来实现这些已经是小菜一碟了,因为这些API全部是前面的封装而已。

1. 实现 Promise.resolve

Promise.resolve(value) 将给定的一个值转为Promise对象。

  • 如果这个值是一个 promise ,那么将返回这个 promise ;
  • 如果这个值是thenable(即带有"then"方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
  • 否则返回的promise将以此值完成,即以此值执行resolve()方法 (状态为fulfilled)。

根据规范我们这样实现(写法一):

class myPromise {
   
    ...
}

function resolvePromise(promise2, x, resolve, reject) {
   
    ...
}

/**
 * Promise.resolve()
 * @param {[type]} value 要解析为 Promise 对象的值 
 */
+ myPromise.resolve = function (value) {
   
+     // 如果这个值是一个 promise ,那么将返回这个 promise 
+     if (value instanceof myPromise) {
   
+         return value;
+     } else if (value instanceof Object && 'then' in value) {
   
+         // 如果这个值是thenable(即带有`"then" `方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
+         return new myPromise((resolve, reject) => {
   
+             value.then(resolve, reject);
+         })
+     }
+     
+     // 否则返回的promise将以此值完成,即以此值执行`resolve()`方法 (状态为fulfilled)
+     return new myPromise((resolve) => {
   
+         resolve(value)
+     })
+ }

module.exports = myPromise;

使用官方例子测试一下:

const myPromise = require('./promiseOtherAPI');

const promise1 = myPromise.resolve(123);

promise1.then((value) => {
   
  console.log(value);
  // expected output: 123
});

// Resolve一个thenable对象
var p1 = myPromise.resolve({
   
    then: function (onFulfill) {
   
        onFulfill("Resolving");
    }
});
console.log(p1 instanceof myPromise) // true, 这是一个Promise对象

setTimeout(() => {
   
    console.log('p1 :>> ', p1);
}, 1000);

p1.then(function (v) {
   
    console.log(v); // 输出"fulfilled!"
}, function (e) {
   
    // 不会被调用
});

// Thenable在callback之前抛出异常
// myPromise rejects
var thenable = {
   
    then: function (resolve) {
   
        throw new TypeError("Throwing");
        resolve("Resolving");
    }
};

var p2 = myPromise.resolve(thenable);
p2.then(function (v) {
   
    // 不会被调用
}, function (e) {
   
    console.log(e); // TypeError: Throwing
});

输出结果:

true
123
Resolving
TypeError: Throwing
p1 :>> myPromise {
   PromiseState: 'fulfilled', PromiseResult: 'Resolving', onFulfilledCallbacks: Array(1), onRejectedCallbacks: Array(1)}

在这里插入图片描述

测试通过 ✌

静态方法改造

类(class)通过 static 关键字定义静态方法。不能在类的实例上调用静态方法,而应该通过类本身调用。这些通常是实用程序方法,例如创建或克隆对象的功能。

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

写法二、使用静态方法 static:

class myPromise {
   
	...
	
    resolve(result) {
   
		...
    }

    reject(reason) {
   
		...
    }

    then(onFulfilled, onRejected) {
   
		...
    }

    /**
     * Promise.resolve()
     * @param {[type]} value 要解析为 Promise 对象的值 
     */
+   static resolve(value) {
   
+       // 如果这个值是一个 promise ,那么将返回这个 promise 
+       if (value instanceof myPromise) {
   
+           return value;
+       } else if (value instanceof Object && 'then' in value) {
   
+           // 如果这个值是thenable(即带有`"then" `方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
+           return new myPromise((resolve, reject) => {
   
+               value.then(resolve, reject);
+           })
+       }
+
+       // 否则返回的promise将以此值完成,即以此值执行`resolve()`方法 (状态为fulfilled)
+       return new myPromise((resolve) => {
   
+           resolve(value)
+       })
+   }
}

function resolvePromise(promise2, x, resolve, reject) {
   
	...
}

module.exports = myPromise;

2. 实现 Promise.reject

Promise.reject()方法返回一个带有拒绝原因的Promise对象。

官方例子:

Promise.reject(new Error('fail')).then(function() {
   
  // not called
}, function(error) {
   
  console.error(error); // Stacktrace
});

输出结果:
在这里插入图片描述
根据规范我们这样实现(写法一):

class myPromise {
   
	...
}

function resolvePromise(promise2, x, resolve, reject) {
   
	...
}

myPromise.resolve = function (value) {
   
	...
}

/**
 * myPromise.reject
 * @param {*} reason 表示Promise被拒绝的原因
 * @returns 
 */
+ myPromise.reject = function (reason) {
   
+     return new myPromise((resolve, reject) => {
   
+         reject(reason);
+     })
+ }

module.exports = myPromise;

使用官方用例测试一下:

const myPromise = require('./promiseOtherAPI')

myPromise.reject(new Error('fail')).then(function () {
   
    // not called
}, function (error) {
   
    console.error(error); // Error: fail
});

输出结果:

Error: fail

在这里插入图片描述
测试通过 ✌

写法二、使用静态方法 static:

class myPromise {
   
	...
	
    resolve(result) {
   
		...
    }

    reject(reason) {
   
		...
    }

    then(onFulfilled, onRejected) {
   
		...
    }

    /**
     * Promise.resolve()
     * @param {[type]} value 要解析为 Promise 对象的值 
     */
    static resolve(value) {
   
        // 如果这个值是一个 promise ,那么将返回这个 promise 
        if (value instanceof myPromise) {
   
            return value;
        } else if (value instanceof Object && 'then' in value) {
   
            // 如果这个值是thenable(即带有`"then" `方法),返回的promise会“跟随”这个thenable的对象,采用它的最终状态;
            return new myPromise((resolve, reject) => {
   
                value.then(resolve, reject);
            })
        }

        // 否则返回的promise将以此值完成,即以此值执行`resolve()`方法 (状态为fulfilled)
        return new myPromise((resolve) => {
   
            resolve(value)
        })
    }

    /**
     * myPromise.reject
     * @param {*} reason 表示Promise被拒绝的原因
     * @returns 
     */
+   static reject(reason) {
   
+       return new myPromise((resolve, reject) => {
   
+           reject(reason);
+       })
+   }
}

function resolvePromise(promise2, x, resolve, reject) {
   
	...
}

module.exports = myPromise;

3. 实现 Promise.prototype.catch

catch() 方法返回一个Promise,并且处理拒绝的情况。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。

事实上, calling obj.catch(onRejected) 内部calls obj.then(undefined, onRejected)。(这句话的意思是,我们显式使用obj.catch(onRejected),内部实际调用的是obj.then(undefined, onRejected))

Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

因此我们可以这样来实现:

class myPromise {
   
	...
	
    then(onFulfilled, onRejected) {
   
		...
    }

+   catch (onRejected) {
   
+       return this.then(undefined, onRejected)
+   }
}

function resolvePromise(promise2, x, resolve, reject) {
   
	...
}

module.exports = myPromise;

就一行代码,我的天,居然这么简单😱

我们用官方例子来测试一下吧

const myPromise = require('./promiseOtherAPI')

var p1 = new myPromise(function (resolve, reject) {
   
    resolve('Success');
});

p1.then(function (value) {
   
    console.log(value); // "Success!"
    throw 'oh, no!';
}).catch(function (e) {
   
    console.log(e); // "oh, no!"
}).then(function () {
   
    console.log('after a catch the chain is restored');
}, function () {
   
    console.log('Not fired due to the catch');
});

// 以下行为与上述相同
p1.then(function (value) {
   
    console.log(value); // "Success!"
    return Promise.reject('oh, no!');
}).catch(function (e) {
   
    console.log
;