如何手写Promise?
在JavaScript中,手写一个 Promise
类需要实现它的基本功能,包括状态管理(pending、fulfilled、rejected)和处理异步操作。我们需要实现以下几个关键部分:
状态管理:
Promise
有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。处理器队列:在
Promise
变为fulfilled
或rejected
之前,可以将处理器(回调函数)存储起来,在状态改变后再执行这些处理器。then 方法:用于添加处理器,在
Promise
状态改变后执行处理器。resolve 和 reject 方法:用于改变
Promise
的状态。
以下是一个基本的 Promise
实现:
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // fulfilled 或 rejected 的值
this.handlers = []; // 存储 then 的处理器
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.handlers.forEach(handler => handler.onFulfilled(value));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.value = reason;
this.handlers.forEach(handler => handler.onRejected(reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const handle = (callback) => {
try {
const result = callback(this.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
};
if (this.state === 'fulfilled') {
handle(onFulfilled);
} else if (this.state === 'rejected') {
handle(onRejected);
} else {
this.handlers.push({
onFulfilled: (value) => handle(onFulfilled),
onRejected: (reason) => handle(onRejected)
});
}
});
}
}
// 示例使用
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功的结果');
}, 1000);
});
promise.then(result => {
console.log(result); // 输出 "成功的结果"
return '另一个结果';
}).then(result => {
console.log(result); // 输出 "另一个结果"
}).catch(error => {
console.error(error);
});
解释
构造函数:接受一个执行器函数
executor
,该函数会立即执行,并且传递resolve
和reject
函数用于改变Promise
的状态。状态管理:
Promise
有pending
、fulfilled
和rejected
三种状态。初始状态为pending
。处理器队列:在
Promise
变为fulfilled
或rejected
之前,将处理器存储在handlers
数组中。在状态改变后执行这些处理器。then 方法:添加处理器,并返回一个新的
Promise
。在状态改变后执行处理器,并处理链式调用。异步处理:通过
setTimeout
模拟异步操作,展示Promise
的使用。
注意事项
这是一个简化版的
Promise
实现,未处理一些复杂情况,如then
方法中的参数不是函数、Promise
的多次调用、resolve
和reject
的参数是另一个Promise
等。完整的
Promise
实现还需要处理更多的细节和边界情况,如Promise
规范所定义的行为。
Error
node MyPromise.js
/Users/apple/Documents/doc/data/noteoftypora/Learn/MyPromise.js:71
}).catch(error => {
^
TypeError: promise.then(...).then(...).catch is not a function
at Object.<anonymous> (/Users/apple/Documents/doc/data/noteoftypora/Learn/MyPromise.js:71:9)
at Module._compile (internal/modules/cjs/loader.js:1114:14)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
at Module.load (internal/modules/cjs/loader.js:979:32)
at Function.Module._load (internal/modules/cjs/loader.js:819:12)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)
at internal/main/run_main_module.js:17:47
这个错误是因为在我们的简易 Promise
实现中,我们没有实现 catch
方法。为了支持 catch
方法,我们需要在 MyPromise
类中添加 catch
方法。
catch
方法实际上是一个特殊的 then
方法,它只接受一个 onRejected
回调函数。我们可以简单地将 catch
方法实现为一个调用 then
方法的包装器。
以下是更新后的代码,添加了 catch
方法:
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // fulfilled 或 rejected 的值
this.handlers = []; // 存储 then 的处理器
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.handlers.forEach(handler => handler.onFulfilled(value));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.value = reason;
this.handlers.forEach(handler => handler.onRejected(reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
const handle = (callback) => {
try {
const result = callback(this.value);
if (result instanceof MyPromise) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
}
};
if (this.state === 'fulfilled') {
handle(onFulfilled);
} else if (this.state === 'rejected') {
handle(onRejected);
} else {
this.handlers.push({
onFulfilled: (value) => handle(onFulfilled),
onRejected: (reason) => handle(onRejected)
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
}
// 示例使用
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功的结果');
}, 1000);
});
promise.then(result => {
console.log(result); // 输出 "成功的结果"
return '另一个结果';
}).then(result => {
console.log(result); // 输出 "另一个结果"
}).catch(error => {
console.error(error);
});
解释
-
catch 方法:添加了
catch
方法,该方法实际上调用了then
方法,只是onFulfilled
参数为null
,只处理onRejected
回调。
现在,你可以在你的代码中使用 catch
方法了。如果在执行过程中发生错误,catch
回调会被调用。这个更新后的代码应该可以解决你遇到的问题。
完整的 Promise 实现
实现一个完整的 Promise
类,需要遵循 Promises/A+ 规范。这意味着要处理各种复杂情况,比如 thenable 对象、异步执行、链式调用等。以下是一个较为完整的 Promise
实现:
class MyPromise {
constructor(executor) {
this.state = 'pending'; // 初始状态
this.value = undefined; // fulfilled 或 rejected 的值
this.reason = undefined; // rejected 的理由
this.onFulfilledCallbacks = []; // 存储 fulfilled 回调
this.onRejectedCallbacks = []; // 存储 rejected 回调
const resolve = (value) => {
if (this.state === 'pending') {
this.state = 'fulfilled';
this.value = value;
this.onFulfilledCallbacks.forEach(callback => callback(value));
}
};
const reject = (reason) => {
if (this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach(callback => callback(reason));
}
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
// 如果 onFulfilled 或 onRejected 不是函数,则创建默认函数
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
// 返回一个新的 Promise,实现链式调用
return new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
setTimeout(() => {
try {
const result = onFulfilled(this.value);
this.resolvePromise(result, resolve, reject);
} catch (error) {
reject(error);
}
});
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const result = onRejected(this.reason);
this.resolvePromise(result, resolve, reject);
} catch (error) {
reject(error);
}
});
} else if (this.state === 'pending') {
this.onFulfilledCallbacks.push((value) => {
setTimeout(() => {
try {
const result = onFulfilled(value);
this.resolvePromise(result, resolve, reject);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push((reason) => {
setTimeout(() => {
try {
const result = onRejected(reason);
this.resolvePromise(result, resolve, reject);
} catch (error) {
reject(error);
}
});
});
}
});
}
catch(onRejected) {
return this.then(null, onRejected);
}
// 处理 Promise 的解析
resolvePromise(result, resolve, reject) {
if (result === this) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
let called = false;
if (result && (typeof result === 'object' || typeof result === 'function')) {
try {
let then = result.then;
if (typeof then === 'function') {
then.call(result, (value) => {
if (called) return;
called = true;
this.resolvePromise(value, resolve, reject);
}, (reason) => {
if (called) return;
called = true;
reject(reason);
});
} else {
resolve(result);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
resolve(result);
}
}
static resolve(value) {
if (value instanceof MyPromise) {
return value;
}
return new MyPromise((resolve) => resolve(value));
}
static reject(reason) {
return new MyPromise((_, reject) => reject(reason));
}
static all(promises) {
return new MyPromise((resolve, reject) => {
let resolvedCount = 0;
const results = new Array(promises.length);
promises.forEach((promise, index) => {
MyPromise.resolve(promise).then(value => {
resolvedCount++;
results[index] = value;
if (resolvedCount === promises.length) {
resolve(results);
}
}).catch(reject);
});
});
}
static race(promises) {
return new MyPromise((resolve, reject) => {
promises.forEach(promise => {
MyPromise.resolve(promise).then(resolve).catch(reject);
});
});
}
}
// 示例使用
const promise = new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('成功的结果');
}, 1000);
});
promise.then(result => {
console.log(result); // 输出 "成功的结果"
return '另一个结果';
}).then(result => {
console.log(result); // 输出 "另一个结果"
}).catch(error => {
console.error(error);
});
主要功能解释
状态管理:
pending
、fulfilled
和rejected
三种状态。回调队列:在
pending
状态下,回调函数会被存储在队列中,状态改变后执行。then 方法:处理回调并返回新的
Promise
,实现链式调用。catch 方法:专门处理 rejected 状态。
resolvePromise:处理
Promise
解析的各种情况,支持 thenable 对象和循环引用检测。静态方法:实现
resolve
、reject
、all
和race
静态方法,支持更多操作。
这个实现遵循了 Promises/A+
规范,可以处理大部分常见的 Promise
使用场景。