本文共 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/