Promise原理分析与手写简易版Promise
2023-11-23 23:15:42
一、前言:Promise灵魂三问
- Promise是什么?
Promise是JavaScript中用来处理异步操作的工具。它是一个对象,表示一个异步操作的最终完成或失败及其结果值。
- Promise做什么?
Promise可以用来避免回调函数嵌套带来的“回调地狱”问题。它允许我们将异步操作链式调用,使代码更加简洁和易于理解。
- Promise怎么做?
Promise内部采用状态机来管理异步操作的状态。当异步操作完成时,Promise的状态会从“pending”变为“resolved”或“rejected”。状态的改变会触发相应的回调函数,以便我们处理异步操作的结果。
二、Promise的原理剖析
- Promise的状态
Promise有三种状态:“pending”、“resolved”和“rejected”。
- pending: 表示异步操作正在进行中,尚未完成。
- resolved: 表示异步操作已成功完成,并带有结果值。
- rejected: 表示异步操作已失败,并带有错误信息。
- Promise的回调函数
Promise提供两个回调函数:“then”和“catch”。
- then: 用于处理异步操作成功完成的情况。
- catch: 用于处理异步操作失败的情况。
- Promise的链式调用
Promise支持链式调用,即一个Promise的“then”回调函数可以返回另一个Promise,这样我们就可以将多个异步操作串联起来,形成一个异步操作链。
三、手写简易版Promise
下面我们来一步步实现一个简易版的Promise:
- 定义Promise类
class Promise {
constructor(executor) {
this.state = 'pending';
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.state !== 'pending') return;
this.state = 'resolved';
this.value = value;
this.onResolvedCallbacks.forEach((callback) => callback(value));
};
const reject = (reason) => {
if (this.state !== 'pending') return;
this.state = 'rejected';
this.reason = reason;
this.onRejectedCallbacks.forEach((callback) => callback(reason));
};
executor(resolve, reject);
}
then(onResolved, onRejected) {
if (typeof onResolved !== 'function') onResolved = (value) => value;
if (typeof onRejected !== 'function') onRejected = (reason) => { throw reason; };
const promise2 = new Promise((resolve, reject) => {
if (this.state === 'resolved') {
setTimeout(() => {
try {
const x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else if (this.state === 'rejected') {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
} else {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onResolved(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
const x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
});
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected);
}
finally(onFinally) {
return this.then(
(value) => Promise.resolve(onFinally()).then(() => value),
(reason) => Promise.resolve(onFinally()).then(() => { throw reason; })
);
}
static resolve(value) {
return new Promise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new Promise((_, reject) => {
reject(reason);
});
}
static all(promises) {
return new Promise((resolve, reject) => {
const values = [];
let count = 0;
promises.forEach((promise, index) => {
promise.then((value) => {
values[index] = value;
count++;
if (count === promises.length) {
resolve(values);
}
}, reject);
});
});
}
static race(promises) {
return new Promise((resolve, reject) => {
promises.forEach((promise) => {
promise.then(resolve, reject);
});
});
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError('Chaining cycle detected for promise!'));
}
if ((x !== null && typeof x === 'object') || typeof x === 'function') {
let called = false;
try {
const then = x.then;
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
- 使用方法
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Hello, world!');
}, 2000);
});
promise.then((value) => {
console.log(value); // 'Hello, world!'
}).catch((reason) => {
console.log(reason);
});
四、Promise与回调函数和事件循环
- Promise与回调函数
Promise与回调函数都是用来处理异步操作的,但Promise相比回调函数有以下优点:
- 可读性更好: Promise的链式调用使得代码更加简洁易读,避免了回调函数嵌套带来的“回调地狱”问题。
- 易于出错处理: Promise的“catch”回调函数可以方便地处理异步操作失败的情况。
- 支持链式调用: Promise支持链式调用,可以将多个异步操作串联起来,形成一个异步操作链。
- Promise与事件循环
Promise内部使用事件循环来调度异步操作。当一个异步操作完成时,Promise的状态会从“pending”变为“resolved”或“rejected”。状态的改变会触发相应的回调函数,以便我们处理异步操作的结果。
五、结语
Promise是JavaScript中处理异步操作的利器,它可以帮助我们编写更加简洁、易读、易于出错处理的代码。通过对Promise原理的深入剖析和手写简易版Promise的实现,我们对Promise有了更深入的理解。希望本文能帮助你更好地理解和使用Promise,从而提升你的异步编程技能。