在前端开发中,Promise 是一种常见的异步编程解决方案。Promise 可以帮助我们更好地管理异步操作,避免回调地狱。但是,当我们需要多次调用.then() 方法时,就会出现一些问题。本文将介绍如何手写 Promise,以解决多次.then() 方法的问题。
Promise 的基本概念
Promise 是一种异步编程解决方案,它可以将异步操作转换为同步操作,避免回调地狱。Promise 有三种状态:
- Pending(进行中)
- Fulfilled(已成功)
- Rejected(已失败)
当 Promise 的状态从 Pending 转变为 Fulfilled 或 Rejected 时,就称为 Promise 已经 settled(已完成)。
手写 Promise
接下来,我们将手写一个 Promise,以解决多次.then() 方法的问题。首先,我们需要定义 Promise 的基本结构:
// javascriptcn.com 代码示例 class Promise { constructor(executor) { // Promise 的初始状态为 Pending this.state = 'pending'; // Promise 的结果值 this.value = undefined; // Promise 的错误信息 this.reason = undefined; // 存储 then 方法的回调函数 this.onResolvedCallbacks = []; this.onRejectedCallbacks = []; // 执行 executor 函数 try { executor(this.resolve.bind(this), this.reject.bind(this)); } catch (error) { this.reject(error); } } // Promise 的 resolve 方法 resolve(value) { // 只有在 Promise 的状态为 Pending 时才能转变为 Fulfilled if (this.state === 'pending') { this.state = 'fulfilled'; this.value = value; // 执行 then 方法的回调函数 this.onResolvedCallbacks.forEach(callback => callback()); } } // Promise 的 reject 方法 reject(reason) { // 只有在 Promise 的状态为 Pending 时才能转变为 Rejected if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; // 执行 then 方法的回调函数 this.onRejectedCallbacks.forEach(callback => callback()); } } // Promise 的 then 方法 then(onFulfilled, onRejected) { // 如果 onFulfilled 或 onRejected 不是函数,则忽略它们 onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value; onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }; // 创建一个新的 Promise const promise2 = new Promise((resolve, reject) => { if (this.state === 'fulfilled') { // 如果 Promise 的状态为 Fulfilled,则执行 onFulfilled 方法 setTimeout(() => { try { const x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } else if (this.state === 'rejected') { // 如果 Promise 的状态为 Rejected,则执行 onRejected 方法 setTimeout(() => { try { const x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); } else { // 如果 Promise 的状态为 Pending,则将回调函数存储起来 this.onResolvedCallbacks.push(() => { setTimeout(() => { try { const x = onFulfilled(this.value); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); this.onRejectedCallbacks.push(() => { setTimeout(() => { try { const x = onRejected(this.reason); this.resolvePromise(promise2, x, resolve, reject); } catch (error) { reject(error); } }, 0); }); } }); return promise2; } // 解决 Promise 返回值的问题 resolvePromise(promise2, x, resolve, reject) { if (promise2 === x) { return reject(new TypeError('Chaining cycle detected for promise')); } let called = false; if (x instanceof Promise) { x.then(value => { this.resolvePromise(promise2, value, resolve, reject); }, reason => { if (called) return; called = true; reject(reason); }); } else if (x !== null && (typeof x === 'object' || typeof x === 'function')) { try { const then = x.then; if (typeof then === 'function') { then.call(x, value => { if (called) return; called = true; this.resolvePromise(promise2, value, resolve, reject); }, reason => { if (called) return; called = true; reject(reason); }); } else { resolve(x); } } catch (error) { if (called) return; called = true; reject(error); } } else { resolve(x); } } }
在上述代码中,我们定义了 Promise 的基本结构,并实现了 Promise 的 resolve、reject 和 then 方法。同时,我们还实现了 Promise 返回值的处理,以解决多次.then() 方法的问题。
示例代码
接下来,我们将使用上述手写的 Promise,并编写一段示例代码:
// javascriptcn.com 代码示例 const promise = new Promise((resolve, reject) => { setTimeout(() => { resolve('Hello, Promise!'); }, 1000); }); promise .then(value => { console.log(value); return new Promise(resolve => { setTimeout(() => { resolve('Hello, Promise again!'); }, 1000); }); }) .then(value => { console.log(value); });
在上述代码中,我们定义了一个 Promise,它将在 1 秒钟后 resolved,并输出字符串 'Hello, Promise!'。然后,我们使用第一个.then() 方法返回一个新的 Promise,它将在 1 秒钟后 resolved,并输出字符串 'Hello, Promise again!'。
通过运行上述代码,我们可以看到,它成功地解决了多次.then() 方法的问题,并输出了两个字符串。
总结
通过手写 Promise,我们深入了解了 Promise 的基本概念和实现方式,并解决了多次.then() 方法的问题。在实际开发中,我们可以使用 Promise 来更好地管理异步操作,提高代码的可读性和可维护性。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/656fd96fd2f5e1655d844107