自己写一个Promise

Posted lhlvs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己写一个Promise相关的知识,希望对你有一定的参考价值。

参考Promise 的  官方规范  https://promisesaplus.com/

Promise 其实就是一个状态机

它只有两种状态变化 pending    =》   fulfilled

         pending    =》   rejected

并且状态一旦发生变化后就不会再改变

我们用es5来实现下

先写个架子, 并测试下:

function myPromise(executor) {
    var _this = this; // 保存当前的函数上下文
    _this.status = ‘pending‘; // 初始状态
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    function resolve(value) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Fulfilled‘;
            _this.resolveValue = value;
        }
    }
    function reject(reason) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Fulfilled‘;
            _this.rejectValue = reason;
        }
    }
    try {    // 捕获错误
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    if (_this.status == ‘Fulfilled‘) {
        onFulfilled(_this.resolveValue)
    }
    if (_this.status == ‘Rejected‘) {
        onRejected(_this.rejectValue)
    }
};

var p = new myPromise((resolve, reject) => {
    resolve(‘I am handsome‘);
    throw Error(‘捕获错误‘)
});
p.then((data) => {
    console.log(data)
}, (err) => {
    console.log(err)
} );

结果:

技术图片

它先执行resolve   状态 变为   Fulfilled    ,

然后报错 ,执行reject , 由于此时状态不是pending, 状态还是Fulfilled

Promise的核心是处理异步,

现在我们的代码并不能等待状态的改变,

接下来我们加上处理异步操作的功能, 并测试下

function myPromise(executor) {
    var _this = this; // 保存当前的函数上下文
    _this.status = ‘pending‘; // 初始状态
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    _this.resolveCallbackList = []; // 存resolve的回调
    _this.rejectCallbackList = []; // 存reject的回调
    function resolve(value) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Fulfilled‘;
            _this.resolveValue = value;
            // 状态改变执行存的回调
            _this.resolveCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    function reject(reason) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Rejected‘;
            _this.rejectValue = reason;
            // 状态改变执行存的回调
            _this.rejectCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    try {    // 捕获错误
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    if (_this.status == ‘Fulfilled‘) {
        onFulfilled(_this.resolveValue)
    }
    if (_this.status == ‘Rejected‘) {
        onRejected(_this.rejectValue)
    }
    // 等待状态时把回调存起来,状态改变再触发
    if (_this.status == ‘pending‘) {
        _this.resolveCallbackList.push(function () {
            onFulfilled(_this.resolveValue)
        });
        _this.rejectCallbackList.push(function () {
            onRejected(_this.rejectValue)
        });
    }
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(‘I am handsome‘);
    }, 0);
    // throw Error(‘捕获错误‘)
});
p.then((data) => {
    console.log(data)
}, (err) => {
    console.log(err)
} );

结果:

技术图片

 

 ??  它已经能处理异步操作了

 

接下来实现链式操作, 再测试下

function myPromise(executor) {
    var _this = this; // 保存当前的函数上下文
    _this.status = ‘pending‘; // 初始状态
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    _this.resolveCallbackList = []; // 存resolve的回调
    _this.rejectCallbackList = []; // 存reject的回调
    function resolve(value) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Fulfilled‘;
            _this.resolveValue = value;
            // 状态改变执行存的回调
            _this.resolveCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    function reject(reason) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Rejected‘;
            _this.rejectValue = reason;
            // 状态改变执行存的回调
            _this.rejectCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    try {    // 捕获错误
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    // 用于链式调用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == ‘Fulfilled‘) {
            // 存一下回调执行的结果,传给下一个.then
            var nextResolveValue = onFulfilled(_this.resolveValue);
            res(nextResolveValue);
        }
        if (_this.status == ‘Rejected‘) {
            // 存一下回调执行的结果,传给下一个.then
            var nextRejectValue = onRejected(_this.rejectValue);
            rej(nextRejectValue);
        }
        // 等待状态时把回调存起来,状态改变再触发
        if (_this.status == ‘pending‘) {
            _this.resolveCallbackList.push(function () {
                // 存一下回调执行的结果,传给下一个.then
                var nextResolveValue = onFulfilled(_this.resolveValue);
                res(nextResolveValue);
            });
            _this.rejectCallbackList.push(function () {
                var nextRejectValue = onRejected(_this.rejectValue);
                rej(nextRejectValue);
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(‘I am handsome‘);
    }, 0);
    // throw Error(‘捕获错误‘)
});
p.then((data) => {
    console.log(data + ‘ suc‘ + ‘ 1‘)
    return 222
}, (err) => {
    console.log(err)
} ).then((data) => {
    console.log(data + ‘ suc‘ + ‘ 2‘)
}, (err) => {
    console.log(err)
} );

结果 :

技术图片

没毛病, 可以链式调用then了  , 先不处理返回值为Promise  的 情况  ,

原生的Promise 执行方法都是异步的  , 并且执行方法是能捕捉错误,

我们加上这个功能 , 并且测试下

function myPromise(executor) {
    var _this = this; // 保存当前的函数上下文
    _this.status = ‘pending‘; // 初始状态
    _this.resolveValue = null;  // resolve初始值
    _this.rejectValue = null;  // reject初始值
    _this.resolveCallbackList = []; // 存resolve的回调
    _this.rejectCallbackList = []; // 存reject的回调
    function resolve(value) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Fulfilled‘;
            _this.resolveValue = value;
            // 状态改变执行存的回调
            _this.resolveCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    function reject(reason) {
        if (_this.status ==  ‘pending‘) {
            _this.status = ‘Rejected‘;
            _this.rejectValue = reason;
            // 状态改变执行存的回调
            _this.rejectCallbackList.forEach(function(ele){
                if (ele) {
                    ele();
                }
            })
        }
    }
    try {    // 捕获错误
        executor(resolve, reject)
    } catch (e){
        reject(e);
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    var _this = this;
    // 用于链式调用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == ‘Fulfilled‘) {
            // 存一下回调执行的结果,传给下一个.then
            setTimeout(function () {
                // 捕获错误
                try {
                    var nextResolveValue = onFulfilled(_this.resolveValue);
                    res(nextResolveValue);
                } catch (e) {
                    rej(e)
                }

            },0)
        }
        if (_this.status == ‘Rejected‘) {
            // 存一下回调执行的结果,传给下一个.then
            setTimeout(function () {
                // 捕获错误
                try {
                    var nextRejectValue = onRejected(_this.rejectValue);
                    rej(nextRejectValue);
                } catch (e) {
                    rej(e)
                }
            },0)
        }
        // 等待状态时把回调存起来,状态改变再触发
        if (_this.status == ‘pending‘) {
            _this.resolveCallbackList.push(function () {
                // 存一下回调执行的结果,传给下一个.then
                setTimeout(function () {
                    // 捕获错误
                    try {
                        var nextResolveValue = onFulfilled(_this.resolveValue);
                        res(nextResolveValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
            _this.rejectCallbackList.push(function () {
                setTimeout(function () {
                    // 捕获错误
                    try {
                        var nextRejectValue = onRejected(_this.rejectValue);
                        rej(nextRejectValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(‘I am handsome‘);
        console.log(111)
    }, 0);
    // throw Error(‘捕获错误‘)
});
p.then((data) => {
    console.log(data + ‘ suc‘ + ‘ 1‘);
    throw Error(‘bao cuo‘)
}, (err) => {
    console.log(err + ‘ err‘ + ‘ 1‘)
} ).then((data) => {
    console.log(data + ‘ suc‘ + ‘ 2‘)
}, (err) => {
    console.log(err + ‘ err‘ + ‘ 2‘)
} );
console.log(222);

预期结果  222  =》 111 =》 I am handsome suc 1    =》   Error: bao cuo err 2

实际结果:

技术图片

 

 没毛病, 异步并且捕获到错误了

我们再来处理 空 then()    就是then里面不传参数的情况, 并测试

myPromise.prototype.then = function (onFulfilled, onRejected) {
    // 参数为空把值直接传给下一个then
    if (!onFulfilled) {
        onFulfilled = function (val) {
            return val;
        }
    }
    if (!onRejected) {
        onRejected = function (val) {
            return new Error(val)
        }
    }
    var _this = this;
    // 用于链式调用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == ‘Fulfilled‘) {
            // 存一下回调执行的结果,传给下一个.then
            setTimeout(function () {
                // 捕获错误
                try {
                    var nextResolveValue = onFulfilled(_this.resolveValue);
                    res(nextResolveValue);
                } catch (e) {
                    rej(e)
                }

            },0)
        }
        if (_this.status == ‘Rejected‘) {
            // 存一下回调执行的结果,传给下一个.then
            setTimeout(function () {
                // 捕获错误
                try {
                    var nextRejectValue = onRejected(_this.rejectValue);
                    rej(nextRejectValue);
                } catch (e) {
                    rej(e)
                }
            },0)
        }
        // 等待状态时把回调存起来,状态改变再触发
        if (_this.status == ‘pending‘) {
            _this.resolveCallbackList.push(function () {
                // 存一下回调执行的结果,传给下一个.then
                setTimeout(function () {
                    // 捕获错误
                    try {
                        var nextResolveValue = onFulfilled(_this.resolveValue);
                        res(nextResolveValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
            _this.rejectCallbackList.push(function () {
                setTimeout(function () {
                    // 捕获错误
                    try {
                        var nextRejectValue = onRejected(_this.rejectValue);
                        rej(nextRejectValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(‘I am handsome‘);
    }, 0);
    // throw Error(‘捕获错误‘)
});
p.then((data) => {
    console.log(data + ‘ suc‘ + ‘ 1‘);
    throw Error(‘bao cuo‘)
}, (err) => {
    console.log(err + ‘ err‘ + ‘ 1‘)
} ).then( ).then((data) => {
    console.log(data + ‘ suc‘ + ‘ 3‘)
}, (err) => {
    console.log(err + ‘ err‘ + ‘ 3‘)
} );

结果:

技术图片

 

??  第一个then里抛出的错误被第三个then 接受到了, 没毛病

接下来处理 返回值为promise的情况, 并测试

如果返回值为promise,后面的then就取决于返回的promise的状态

// 处理返回值的函数
function ResolutionRetrunPromise (nextPromise, returnValue, res, rej) {
    // 返回值是否是promise
    if (returnValue instanceof  myPromise) {
        returnValue.then(function (val) {
            res(val)
        },function (reason) {
            rej(reason)
        })
    } else {
        res(returnValue)
    }
}
myPromise.prototype.then = function (onFulfilled, onRejected) {
    // 参数为空把值直接传给下一个then
    if (!onFulfilled) {
        onFulfilled = function (val) {
            return val;
        }
    }
    if (!onRejected) {
        onRejected = function (reason) {
            return new Error(reason)
        }
    }
    var _this = this;
    // 用于链式调用
    var nextPromise = new myPromise(function(res, rej) {
        if (_this.status == ‘Fulfilled‘) {
            // 存一下回调执行的结果,传给下一个.then
            setTimeout(function () {
                // 捕获错误
                try {
                    var nextResolveValue = onFulfilled(_this.resolveValue);
                    // 处理返回值
                    ResolutionRetrunPromise(nextPromise, nextResolveValue, res, rej)
                    // res(nextResolveValue);
                } catch (e) {
                    rej(e)
                }

            },0)
        }
        if (_this.status == ‘Rejected‘) {
            // 存一下回调执行的结果,传给下一个.then
            setTimeout(function () {
                // 捕获错误
                try {
                    var nextRejectValue = onRejected(_this.rejectValue);
                    ResolutionRetrunPromise(nextPromise, nextRejectValue, res, rej)
                    // rej(nextRejectValue);
                } catch (e) {
                    rej(e)
                }
            },0)
        }
        // 等待状态时把回调存起来,状态改变再触发
        if (_this.status == ‘pending‘) {
            _this.resolveCallbackList.push(function () {
                // 存一下回调执行的结果,传给下一个.then
                setTimeout(function () {
                    // 捕获错误
                    try {
                        var nextResolveValue = onFulfilled(_this.resolveValue);
                        ResolutionRetrunPromise(nextPromise, nextResolveValue, res, rej)
                        // res(nextResolveValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
            _this.rejectCallbackList.push(function () {
                setTimeout(function () {
                    // 捕获错误
                    try {
                        var nextRejectValue = onRejected(_this.rejectValue);
                        ResolutionRetrunPromise(nextPromise, nextRejectValue, res, rej)
                        // rej(nextRejectValue);
                    } catch (e) {
                        rej(e)
                    }
                },0)
            });
        }
    });
    return nextPromise
};

var p = new myPromise((resolve, reject) => {
    setTimeout(() => {
        resolve(‘I am handsome‘);
    }, 1000);
});
p.then((data) => {
    console.log(data + ‘ suc‘ + ‘ 1‘);
    return new myPromise((resolve, reject) => {
        reject(‘promise‘)
    })
}, (err) => {
    console.log(err + ‘ err‘ + ‘ 1‘)
} ).then((data) => {
    console.log(data + ‘ suc‘ + ‘ 3‘)
}, (err) => {
    console.log(err + ‘ err‘ + ‘ 3‘)
} );

 

 结果:技术图片

到此 Promise 的 基本功能就实现了  , 

感兴趣的同学可以基于此 自己实现一下Promise 的   静态方法 。 。 。 。。 。 

 

以上是关于自己写一个Promise的主要内容,如果未能解决你的问题,请参考以下文章

自己写一个Promise

前端面试题之手写promise

创建自己的代码片段(CodeSnippet)

关于学习js的Promise的心得体会

深入理解Promise并写一个符合Promise a+规范的Promise代码

Mongoose:用 promise 编写自己的方法