校验promiseA+规范

此时我们可以安装一个工具来测试是否符合 promiseA+ 规范:promises-aplus-tests

  1. npm i -D promises-aplus-tests

运行命令

  1. promises-aplus-tests myPromise3.js // 文件名
  2. // package.json
  3. "test": "promises-aplus-tests ./myPromise3.js"
  1. var d = adapter.deferred();
  2. TypeError: adapter.deferred is not a function

这时要在 myPromise.js 加入这段代码

  1. MyPromise.defer = MyPromise.deferred = function () {
  2. let deferred = {}
  3. deferred.promise = new MyPromise((resolve, reject) => {
  4. deferred.resolve = resolve
  5. deferred.reject = reject
  6. })
  7. return deferred
  8. }

再次启动即可

实现resolve与reject的静态方法

  1. static resolve(value) {
  2. return new MyPromise((resolve,reject)=>{
  3. resolve(value)
  4. })
  5. }
  6. static reject(reason){
  7. return new MyPromise((resolve,reject)=>{
  8. reject(reason)
  9. })
  10. }

同时要对 resolve进行改造,否则会忽略异步中的新的Promise

  1. const resolve = (value) => {
  2. // 校验一下是否为一个MyPromise,是的话就继续走then,否则会直接把异步Promise执行掉
  3. if (value instanceof MyPromise) {
  4. value.then((res) => {
  5. resolve(res)
  6. }, reject)
  7. return
  8. }
  9. if (this.state === "PENDING") {
  10. this.state = FULFILLED;
  11. this.value = value
  12. // 执行等待事件
  13. this.onFulfilledCallbacks.forEach(item => {
  14. item()
  15. })
  16. }
  17. }

实现promise.all

原理:传入一个数组,数组里面的每一个Promise都成功了,才会成功,返回一个结果为数组,数组里的每一项则是对应的Promise的成功结果;若有其中一个失败,则会失败,用catch捕获其中的报错信息

static all(promiseArr) {
        let resArr = [],
            idx = 0;
        return new MyPromise((resolve, reject) => {
            promiseArr.map((promise, index) => {
                if (isPromise(promise)) {
                    promise.then(res => {
                        (fomatResArr(res, index, resolve))
                    }, reject)
                } else {
                    fomatResArr(res, index, resolve)
                }
            })
        })

        function isPromise(promise) {
            if ((typeof promise === "object" && typeof promise !== null) || typeof promise === "function") {
                let then = promise.then
                return typeof then === "function"
            }
        }

        function fomatResArr(res, index, resolve) {
            resArr[index] = res;
            if (++idx === promiseArr.length) {
                resolve(resArr)
            }
        }
    }

实现Promise.allSettled

allSettledall的区别大概有两点

1.不管promise的状态成功与否,都会返回到最终结果上

2.如果传进去的不是一个数组或者可迭代对象,会报错的

所以加一个isIterable去判断是否可迭代

function isIterable(value) {
    return value !== null && value !== undefined && typeof value[Symbol.iterator] === 'function'
}
static allSettled(promiseArr) {
        let resArr = [],
            idx = 0;
        if (!isIterable(promiseArr)) {
            throw new TypeError(promiseArr + 'is not iterable')
        }
        return new MyPromise((resolve, reject) => {
            if (promiseArr.length === 0) {
                resolve([])
            }
            promiseArr.map((promise, index) => {
                if (isPromise(promise)) {
                    promise.then((value) => {
                        formatResArr("fulfilled", value, index, resolve)
                    }, (reason) => {
                        formatResArr("rejected", reason, index, resolve)
                    })
                } else {
                    formatResArr("fulfilled", value, index, resolve)
                }

            })

            function formatResArr(status, value, index, resolve) {
                switch (status) {
                    case "fulfilled":
                        resArr[index] = {
                            status,
                            value
                        };
                        break;
                    case "rejected":
                        resArr[index] = {
                            status,
                            reason: value
                        };
                        break
                }
                if (++idx === promiseArr.length) {
                    resolve(resArr)
                }
            }
        })
    }

实现Promise.race与finally

race:谁先有结果,就拿谁的结果

  static race(promiseArr) {
        return new MyPromise((resolve, reject) => {
            promiseArr.map((promise) => {
                if (isPromise(promise)) {
                    // 谁快就谁先改状态,就返回谁
                    promise.then(resolve, reject)
                } else {
                    resolve(promise)
                }
            })
        })
 }

finally:先来看几个例子

// 外面是成功
Promise.resolve("promise resolve").finally(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // resolve("new Promise")// 都成功,取外面,promise resolve
            reject("new Promise reject") // // 里面失败,取里面 new Promise reject
        }, 1000)
    })
}).then(res => {
    console.log("res:", res);
}).catch(err => {
    console.log("err:", err);
})

// 外面是失败
Promise.reject("promise reject").finally(() => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // resolve("new Promise resolve") // 外面失败,里面成功,取外面 promise reject
            reject("new Promise reject") // // 都失败,取里面 new Promise reject
        }, 1000)
    })
}).then(res => {
    console.log("res:", res);
}).catch(err => {
    console.log("err:", err);
})

1.无论外面的Promise成功还是失败,都要走,并且回调不带参数

2.正常走finally之后then或者catch

3.如果finally内部有Promise并且有延时处理,整个finally会等待

4.如果两个都是成功,取外面的结果

5.如果外面是成功,里面是失败,取里面的结果(失败)

6.如果外面是失败,里面是成功,取外面的结果(失败)

7.如果外面是失败,里面是失败,去里面的结果(失败)

8.如果外面是成功,里面是成功,取外面的结果(成功)

总结:只有里面失败了就会失败,并取里面的结果,只有都成功的时候才会取外面成功的结果

// finally实现

finally(finallyCallback) {
        return this.then(
            (value) => {
                let p = MyPromise.resolve(finallyCallback()).then((res) => {
                    return value
                })

                return p
            },
            (reason) => {
                return MyPromise.resolve(finallyCallback()).then(() => {
                    throw reason
                })
            })
    }

实现promisify与promisifyAll

什么是promisify:将一个函数promise化,使之可以进行.then操作

const fs = require('fs')
fs.readFile("./data/user.json", "utf-8", function (err, data) {
    if (err) {
        console.log(err);
        return
    }
    console.log(data);
})

// 当我们需要把readFile变成异步时例如,则需要promiseify
fs.readFile("./data/user.json", "utf-8").then(res => {
    console.log(res);
})

工具实现:blueBird或者node自带的uitl都带有promisify的方法

const readFile = blueBird.promisify(fs.readFile) 
const util = require('util')
const readFile = util.promisify(fs.readFile)

手写实现

 promisify(fn) {
        return function (...arg) {
            return new Promise((resolve, reject) => {
                // 这里主要因为fs的函数一般都是这种形式
                fn(...arg, (err, data) => {
                    if (err) {
                        return reject(err)

                    }
                    resolve(data)
                })
            })
        }
    }

    // 就是将一个对象里的所有函数都变成promise
    promisifyAll(fns) {
        Object.keys(fns).map((fnName) => {
            if (typeof fns[fnName] === "function") {
                fns[fnName + 'Async'] = this.promisify(fns[fnName])
            }
        })
        return fns
    }