promise A+规范

117 阅读2分钟

基础版Promise

//手写Promise源码
const Promise = function Promise(executor) {
    let self = this;
    //参数错误判断
    if (toType(executor) !== 'function') throw Error('Promise resolver ' + toType(executor) + ' is not a function');
	 //new Promise() self的__proto__会指向Promise   直接Promise() this指向window
     if (!(self instanceof Promise)) throw new TypeError('undefined is not a promise');

    self.state = 'pending';
    self.value = undefined;
    self.onfulfilledCallbacks = [];
    self.onrejectedCabacks = [];

    // 修改状态
    const change = function change(state, value) {
        //只有初始值在pending的时候才能修改
        if (self.state !== 'pending') return;
        self.state = state;
        self.value = value;
        setTimeout(() => {
            var callbacks = self.state === 'fulfilled' ? self.onfulfilledCallbacks : self.onrejectedCabacks;
            for (var i = 0; i < callbacks.length; i++) {
                callbacks[i](self.value);
            }
        });
    }

    try {
        executor(function (result) {
            change('fulfilled', result);
        }, function (reason) {
            change('rejected', reason);
        })
    } catch (err) {
        change('rejected', err.message);
    }

    return self
}

// Promise原型链上的方法
Promise.prototype = {
    constructor: Promise,
    then: function then(onfulfilled, onrejected) {
        let self = this;
        switch (self.state) {
            case 'fulfilled':
                setTimeout(() => {
                    onfulfilled(self.value);
                });
                break;
            case 'rejected':
                setTimeout(() => {
                    onrejected(self.value);
                });
                break;
            default:
                self.onfulfilledCallbacks.push(onfulfilled);
                self.onrejectedCabacks.push(onrejected);
        }
    },
    catch: function MyCatch() {}    
}

if (typeof (Symbol) !== "undefined") Promise.prototype[Symbol.toStringTag] = 'Promise';

let P = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(100);
    }, 1000);
})

P.then((res) => {
    console.log(res)
})

进阶版Promise

//手写Promise源码
const Promise = function Promise(executor) {
    let self = this;
    //参数错误判断
    if (toType(executor) !== 'function') throw Error('Promise resolver ' + toType(executor) + ' is not a function');

    if (!(self instanceof Promise)) throw new TypeError('undefined is not a promise');

    self.state = 'pending';
    self.value = undefined;
    self.onfulfilledCallbacks = [];
    self.onrejectedCabacks = [];

    // 修改状态
    const change = function change(state, value) {
        //只有初始值在pending的时候才能修改
        if (self.state !== 'pending') return;
        // 状态立马该
        self.state = state;
        self.value = value;
        // 执行是用宏任务定时器模拟微任务 queueMicrotask
        setTimeout(() => {
            var callbacks = self.state === 'fulfilled' ? self.onfulfilledCallbacks : self.onrejectedCabacks;
            for (var i = 0; i < callbacks.length; i++) {
                callbacks[i](self.value);
            }
        });
    }

    try {
        executor(function (result) {
            change('fulfilled', result);
        }, function (reason) {
            change('rejected', reason);
        })
    } catch (err) {
        change('rejected', err.message);
    }

    return self
}

//优化
const handle = function handle(callback, value,resolve,reject) {
    try {
        //返回的Promise的状态是由onfulfilled函数return 了什么决定的
        let result = callback(value);
        // 检测result是不是一个Promise
        if (result instanceof Promise) {
            //再递归调用then 他会根据状态帮我选择是resolve(value)还是reject(value) 还是先存储数组
            result.then(resolve, reject);
            return;
        };
        // 如果不是promise 把他变成fulfilled 值为result
        resolve(result);
    } catch (err) {
        reject(err.message)
    }
}

// Promise原型链上的方法
Promise.prototype = {
    constructor: Promise,
    then: function then(onfulfilled, onrejected) {
        let self = this;
        return new Promise((resolve, reject) => {
            switch (self.state) {
                case 'fulfilled':
                    setTimeout(() => {
                        handle(onfulfilled,self.value,resolve, reject);
                    });
                    break;
                case 'rejected':
                    setTimeout(() => {
                        handle(onrejected,self.value,resolve, reject);
                    });
                    break;
                default:
                    self.onfulfilledCallbacks.push((value) => {
                        handle(onfulfilled,value,resolve, reject);
                    });
                    self.onrejectedCabacks.push((value) => {
                        handle(onrejected,self.value,resolve, reject);
                    });
            }
        })
    },
    catch: function MyCatch(onrejected) {

    }
}

//Promise 静态工具方法
Promise.resolve = function resolve(result) {
    return new Promise((resolve) => {
        resolve(result);
    })
}

Promise.catch = function MyCatch(reason) {
    return new Promise((_, reject) => {
        reject(reason);
    })
}

Promise.all = function resolve() {

}

if (typeof (Symbol) !== "undefined") Promise.prototype[Symbol.toStringTag] = 'Promise';

/* let P = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve(100);
    }, 1000);
    // resolve(100);
})

let t = P.then((res) => {
    console.log(res);
    return Promise.resolve(1000);
}).then((res) => {
    console.log(res)
}) */

const query = function query(time){
    return new Promise((resolve,reject) => {
        setTimeout(() => {
            resolve(time);
        }, time);
    })
}

query(1000).then((result) => {
    console.log(result);
    return query(2000)
}).then((result) => {
    console.log(result)
})

符合Promise A+规范

promisesaplus.com

~function () {
    const Promise = function Promise(execute) {
        let self = this;

        self.state = 'pending';
        self.value = undefined;
        self.onfulfilledCallbacks = [];
        self.onrejectedCallbacks = [];

        const change = function change(state, value) {
            if (self.state !== 'pending') return;
            self.state = state;
            self.value = value;
            queueMicrotask(() => {
                let Callbacks = self.state === 'fulfilled' ? self.onfulfilledCallbacks : self.onrejectedCallbacks;
                Callbacks.forEach(v => {
                    v(self.value)
                })
            })
        }

        try {
            execute(function onfulfilled(value) {
                change('fulfilled', value)
            }, function onrejected(value) {
                change('rejected', value)
            })
        } catch (error) {
            change('rejected', error)
        }
    }

    const resolvePromise = function resolvePromise(promise, x, resolve, reject) {
        if (promise === x) throw new TypeError('kk');
        if (x!==null && /^(object|function)$/i.test(typeof x)) {
            var then;
            try {
                then = x.then;
            } catch (error) {
                reject(error);
            }
            if (typeof then === 'function') {
                let called = false;
                try {
                    then.call(x, function onresolve(y) {
                        if (called) return;
                        called = true;
                        resolvePromise(promise, y, resolve, reject)
                    }, function onreject(value) {
                        if (called) return;
                        called = true;
                        reject(value);
                    })
                } catch (error) {
                    if (called) return;
                    reject(error);
                }
                return;
            }
        }
        resolve(x);
    }

    const handle = function handle(callback, value, promise, resolve, reject) {
        try {
            let x = callback(value);
            resolvePromise(promise, x, resolve, reject);
        } catch (err) {
            reject(err);
        }
    }

    Promise.prototype = {
        constructor: Promise,
        then: function then(onfulfilled, onrejected) {
            let promise = null,
                self = this;

            if (typeof onfulfilled !== 'function') {
                onfulfilled = function onfulfilled(value) {
                    return value
                }
            }

            if (typeof onrejected !== 'function') {
                onrejected = function onrejected(value) {
                    throw value
                }
            }

            promise = new Promise((resolve, reject) => {
                switch (self.state) {
                    case "fulfilled":
                        queueMicrotask(() => {
                            handle(onfulfilled, self.value, promise, resolve, reject)
                        })
                        break;
                    case "rejected":
                        queueMicrotask(() => {
                            handle(onrejected, self.value, promise, resolve, reject)
                        })
                        break;
                    default:
                        self.onfulfilledCallbacks.push(function (value) {
                            handle(onfulfilled, value, promise, resolve, reject)
                        })
                        self.onrejectedCallbacks.push(function (value) {
                            handle(onrejected, value, promise, resolve, reject)
                        })
                }
            })
            return promise
        },
        catch: function Mycatch(onrejected) {
            this.then(null, onrejected);
        }
    }

    Promise.prototype[Symbol.toStringTag] = 'Promise';

    Promise.resolve = function resolve(value) {
        return new Promise((resolve, reject) => {
            resolve(value);
        })
    }

    Promise.reject = function reject(value) {
        return new Promise((resolve, reject) => {
            reject(value);
        })
    }
    
    Promise.all = function all(value) {
        if (!Array.isArray(value)) throw new TypeError('value is not a Array');
        let result = [];
        return new Promise((resolve, reject) => {
            value.forEach((v, i) => {
                if (!isPromise(v)) v = Promise.resolve(v);
                v.then((res) => {
                    result[i] = res;
                    if (result.length >= value.length) resolve(result);
                }).catch((err) => {
                    reject(err);
                })
            })
        })
    }
    
     Promise.race = function race(value) {
        return new Promise((resolve, reject) => {
            if (!Array.isArray(value)) throw new Error(`${value} is not function`);
            value.forEach((v, i) => {
                if (!(v instanceof Promise)) v = Promise.resolve(v);
                v.then((res) => {
                    resolve(res);
                }).catch((err) => {
                    reject(err);
                })
            })
        })
    }

    //测试
    Promise.deferred = function () {
        var result = {};
        result.promise = new Promise(function (resolve, reject) {
            result.resolve = resolve;
            result.reject = reject;
        });
        return result;
    }

    if (typeof window !== 'undefined') window.Promise;
    if (typeof module === 'object' && typeof module.exports === 'object') module.exports = Promise;
}()

调试办法

//初始化
npm init -y
//安装
npm install promises-aplus-tests --save-dev
//手写代码中加入 deferred
Promise.deferred = function () {
  var result = {};
  result.promise = new Promise(function (resolve, reject) {
    result.resolve = resolve;
    result.reject = reject;
  });
  return result;
}
//配置启动命令
{
  "scripts": {
    "test": "promises-aplus-tests MyPromise.js"
  },
  ......
}
//开启调试
npm run test