博客
关于我
手写Promise
阅读量:666 次
发布时间:2019-03-16

本文共 5364 字,大约阅读时间需要 17 分钟。

html标签中的div、head等部分可以删除,只保留核心内容

以下优化后的文章:

代码实现

function _Promise(fn) {            this.status = "pending";            this.data = null;            const _this = this;            this.cacheFn = [];            this.errorObj = { fn: null };         function resolve(data) {            _this.status = "resolved";            _this.data = data;            if (_this.cacheFn.length > 0) {                const fn = _this.cacheFn.shift();                const result = fn(data);                return _this.resultHandler(result);            }        }        function reject(error) {            if (_this.errorObj.fn) {                _this.errorObj.fn(error);            } else {                _this.status = "rejected";                _this.errorObj.error = error;            }        }        try {            fn(resolve, reject);        } catch (error) {            reject(error);        }    }    _Promise.prototype.resultHandler = function (result, isThen) {        if (result instanceof _Promise) {            if (result.errorObj.error !== undefined) {                this.errorObj.error = result.errorObj.error;            }            result.errorObj = this.errorObj;            if (result.status === "resolved") {                const thenFun = this.cacheFn.shift();                result.cacheFn = this.cacheFn;                result.then(thenFun);            } else if (result.status === "pending") {                if (isThen) {                    if (this.cacheFn.length > 0) {                        result.cacheFn = this.cacheFn;                    } else {                        return result;                    }                } else {                    result.cacheFn = this.cacheFn;                }            } else if (result.status === "rejected") {                if (result.errorObj && result.errorObj.fn) {                    result.errorObj.fn(result.errorObj.error);                }            }        }    }    _Promise.prototype.catch = function (fn) {        if (typeof fn !== "function") {            return false;        }        if (this.errorObj) {            this.errorObj.fn = fn;        }    }    _Promise.prototype.then = function (fn) {        if (this.status === "resolved") {            const result = fn(this.data);            return this.resultHandler(result, true);        } else if (this.status === "pending") {            this.cacheFn.push(fn);        }        return this;    }    _Promise.prototype.all = function (fn_arr) {        if (!Array.isArray(fn_arr)) {            throw new Error("参数必须要传递一个数组!");        }        let arr = [];        let cache_resolve = null;        let cache_reject = null;        let hasError = false;        fn_arr.forEach((promise, index) => {            const i = index;            promise.then((value) => {                arr[i] = value;                if (arr.length === fn_arr.length) {                    cache_resolve(arr);                }            }).catch((e) => {                if (hasError) {                    return false;                }                hasError = true;                cache_reject(e);            })        });        return new _Promise((resolve, reject) => {            cache_resolve = resolve;            cache_reject = reject;        });    }    

验证代码

        function test(value) {            return new _Promise((resolve, reject) => {                setTimeout(() => {                    resolve(value);                }, 2000);            });        }        _Promise.all([test(200), test(400), test(700)])            .then((value) => {                console.log(value);            })            .catch((e) => {                console.log(e);            });        test(1000)            .then((value) => {                console.log(1);                return test(value + 100);            })            .then((value) => {                console.log(2);                return new _Promise((resolve, reject) => {                    resolve(value + 500);                });            })            .then((value) => {                console.log(3);                return test(value + 100);            })            .then((value) => {                console.log(value);            })            .catch((e) => {                console.log(e);            });    

分析

简单模式

实现一个Promise的延时调用的特性很容易。Promise对象的状态有pending、resolved和rejected三种。创建一个Promise时,状态初始化为pending,并赋予data属性为null。 当用户在Promise函数中执行同步操作时,逻辑比较简单。执行完毕后调用resolve函数,并将返回值赋予this.data。随后,用户调用then函数时,可以直接访问this.data进行操作。 如果是异步操作,则需要在Promise的构造函数中异步调用fn。由于是异步,需要将then函数中的处理逻辑存入缓存(cacheFn),待resolve函数异步完成后,依次执行缓存中的函数,实现链式调用的特性。

链式调用

链式调用是Promise的一大特性。开发者可以写如then(fn1).then(fn2).then(fn3)的代码。实现这一特性,关键在于如何保证多个then函数的正确执行顺序。 我们通过函数柯里化的思想,每个then函数返回一个新的Promise对象,这样下一个then函数可以继续使用then方法。这样实现了链式调用的模式。 在实现过程中,遇到的难点是异步操作的处理。由于resolve函数是异步的,必须在它执行完毕后才能处理then函数中的逻辑。为了保证链式调用顺序,可以将then函数中的函数存入cacheFn数组,待resolve完成后,依序执行cacheFn中的函数。 这种方式确保了每个then函数可以正确继承上一个Promise的上下文以及缓存信息,从而实现了链式调用的效果。

核心实现思路

Promise的实现关键在于如何处理异步操作的执行顺序以及链式调用带来的递归问题。通过缓存函数(cacheFn)和错误对象(errorObj),可以逐步传递执行上下文。 每次then函数被调用时,若是异步操作,立即存入cacheFn;待resolve函数完成后,依次从cacheFn中取出函数执行。这样可以确保函数的执行顺序,准确实现链式调用。 需要注意的是,当返回值是一个Promise对象时,必须处理其状态并继续执行缓存中的下一个函数。只有这样,才能保证链式调用的连贯性和正确性。

总结

《通过对Promise实现的深入分析,可以看出其核心在于通过缓存函数和错误处理,实现异步操作的同步执行顺序和链式调用的特性。虽然逻辑较为复杂,但通过合理的设计,可以实现高效且简洁的异步代码编写。理解这一点对于优化代码结构和提升开发效率至关重要。

转载地址:http://oxxqz.baihongyu.com/

你可能感兴趣的文章
saas创业八阶段-4、团队复制阶段
查看>>
【AI全栈二】视频流多目标多类别无延迟高精度高召回目标追踪 YOLO+Deepsort 全解
查看>>
2020 祥云杯misc 到点了
查看>>
Linux——系统安全及应用(开关机安全机制、系统弱口令检测、NMAP)
查看>>
C语言共用体union
查看>>
kafka超时错误或者发送消息失败等错误,排错方式
查看>>
Python3 排序函数问题
查看>>
Python3 多线程问题
查看>>
Ubuntu下VirtualBox识别USB教程
查看>>
带你读《企业数据湖》之三:Lambda架构:一种数据湖实现模式
查看>>
Windows下配置单机Hadoop环境 pyspark
查看>>
git教程之远程仓库
查看>>
程序员搞笑动图:告诉你真正的人工智能什么鬼 区块链
查看>>
Android Unable to find explicit activity class问题
查看>>
Vue路由跳转如何传递一个对象过去?
查看>>
sockjs-node/info?t=1462183700002 报错解决方案
查看>>
解决VS Code保存时候自动格式化
查看>>
SAP FI 系列 (027) - 手工发票基于净额计税和基于总额计税录入的区别
查看>>
SAP 修改物料价格那些事
查看>>