Promise() 构造函数
Promise()
构造函数创建 Promise
对象。它主要用于封装尚不支持 Promise 的基于回调的 API。
¥The Promise()
constructor creates Promise
objects. It is primarily used to wrap callback-based APIs that do not already support promises.
Try it
语法
参数
返回值
¥Return value
当通过 new
调用时,Promise
构造函数返回一个 Promise 对象。当调用函数 resolveFunc
或 rejectFunc
时,promise 对象将被解析。请注意,如果调用 resolveFunc
或 rejectFunc
并传递另一个 Promise
对象作为参数,则可以说是 "resolved",但仍然不是 "settled"。请参阅 承诺说明 了解更多说明。
¥When called via new
, the Promise
constructor returns a promise object. The promise object will become resolved when either of the functions resolveFunc
or rejectFunc
are invoked. Note that if you call resolveFunc
or rejectFunc
and pass another Promise
object as an argument, it can be said to be "resolved", but still not "settled". See the Promise description for more explanation.
描述
¥Description
传统上(在 Promise 之前),异步任务被设计为回调。
¥Traditionally (before promises), asynchronous tasks were designed as callbacks.
readFile("./data.txt", (error, result) => {
// This callback will be called when the task is done, with the
// final `error` or `result`. Any operation dependent on the
// result must be defined within this callback.
});
// Code here is immediately executed after the `readFile` request
// is fired. It does not wait for the callback to be called, hence
// making `readFile` "asynchronous".
为了利用 Promise 提供的可读性改进和语言功能,Promise()
构造函数允许将基于回调的 API 转换为基于 Promise 的 API。
¥To take advantage of the readability improvement and language features offered by promises, the Promise()
constructor allows one to transform the callback-based API to a promise-based one.
注意:如果你的任务已经是基于承诺的,你可能不需要
Promise()
构造函数。¥Note: If your task is already promise-based, you likely do not need the
Promise()
constructor.
executor
是自定义代码,它将回调中的结果与承诺联系起来。你,程序员,编写 executor
。其签名预计为:
¥The executor
is custom code that ties an outcome in a callback to a promise. You, the programmer, write the executor
. Its signature is expected to be:
function executor(resolveFunc, rejectFunc) {
// Typically, some asynchronous operation that accepts a callback,
// like the `readFile` function above
}
resolveFunc
和 rejectFunc
也是函数,你可以给它们任何你想要的实际名称。他们的签名很简单:它们接受任何类型的单个参数。
¥resolveFunc
and rejectFunc
are also functions, and you can give them whatever actual names you want. Their signatures are simple: they accept a single parameter of any type.
resolveFunc(value); // call on resolved
rejectFunc(reason); // call on rejected
传递给 resolveFunc
的 value
参数可以是另一个 Promise 对象,在这种情况下,新构造的 Promise 的状态将为传递的 Promise 的 "锁定"(作为 resolution Promise 的一部分)。rejectFunc
的语义与 throw
语句接近,因此 reason
通常是 Error
实例。如果省略 value
或 reason
,则承诺将通过 undefined
履行/拒绝。
¥The value
parameter passed to resolveFunc
can be another promise object, in which case the newly constructed promise's state will be "locked in" to the promise passed (as part of the resolution promise). The rejectFunc
has semantics close to the throw
statement, so reason
is typically an Error
instance. If either value
or reason
is omitted, the promise is fulfilled/rejected with undefined
.
executor
的完成状态对 Promise 状态的影响有限:
¥The executor
's completion state has limited effect on the promise's state:
executor
返回值被忽略。executor
中的return
语句仅影响控制流并改变函数的一部分是否被执行,但对承诺的履行值没有任何影响。如果executor
退出并且将来不可能调用resolveFunc
或rejectFunc
(例如,没有安排异步任务),则 Promise 将永远处于待处理状态。- 如果
executor
中抛出错误,则承诺将被拒绝,除非resolveFunc
或rejectFunc
已被调用。
注意:未决承诺的存在不会阻止程序退出。如果事件循环为空,则程序将退出,尽管有任何待处理的承诺(因为这些承诺必然是永远待处理的)。
¥Note: The existence of pending promises does not prevent the program from exiting. If the event loop is empty, the program exits despite any pending promises (because those are necessarily forever-pending).
以下是典型流程的摘要:
¥Here's a summary of the typical flow:
- 构造函数在生成新的
Promise
对象的同时,还生成了一对对应的resolveFunc
和rejectFunc
函数;这些是 "tethered" 到Promise
对象。 executor
通常封装一些异步操作,提供基于回调的 API。回调(传递给原始基于回调的 API 的回调)是在executor
代码中定义的,因此它可以访问resolveFunc
和rejectFunc
。executor
以resolveFunc
和rejectFunc
函数作为参数同步调用(当Promise
构造完成后)。executor
内的代码有机会执行一些操作。异步任务的最终完成通过resolveFunc
或rejectFunc
引起的副作用与 Promise 实例进行通信。副作用是Promise
对象变成了 "resolved"。- 如果先调用
resolveFunc
,则传递的值将为 resolved。Promise 可能会保持挂起状态(如果另一个 thenable 被传递)、被履行(在大多数情况下,传递了一个不可实现的值)或被拒绝(如果解析值无效)。 - 如果先调用
rejectFunc
,则 Promise 立即被拒绝。 - 一旦调用其中一个解析函数(
resolveFunc
或rejectFunc
),promise 就会保持解析状态。只有对resolveFunc
或rejectFunc
的第一次调用会影响 Promise 的最终状态,而对任一函数的后续调用既不能更改履行值/拒绝原因,也不能将其最终状态从 "fulfilled" 切换到 "rejected" 或相反。 - 如果
executor
通过抛出错误退出,则承诺将被拒绝。但是,如果已调用解析函数之一(以便已解决 Promise),则该错误将被忽略。 - 解决承诺并不一定会导致承诺被履行或拒绝(即解决)。Promise 可能仍处于待处理状态,因为它已通过另一个 thenable 解决,但其最终状态将与已解决的 thenable 的状态相匹配。
- 如果先调用
- 一旦 Promise 确定,它就会(异步)调用通过
then()
、catch()
或finally()
关联的任何其他处理程序。最终的履行值或拒绝原因作为输入参数传递给履行和拒绝处理程序的调用(参见 连锁承诺)。
例如,上面基于回调的 readFile
API 可以转换为基于 Promise 的 API。
¥For example, the callback-based readFile
API above can be transformed into a promise-based one.
const readFilePromise = (path) =>
new Promise((resolve, reject) => {
readFile(path, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
readFilePromise("./data.txt")
.then((result) => console.log(result))
.catch((error) => console.error("Failed to read data"));
resolve
和 reject
回调仅在执行器函数的范围内可用,这意味着在构造 Promise 后你无法访问它们。如果你想在决定如何解决之前构建 Promise,则可以使用 Promise.withResolvers()
方法,该方法公开 resolve
和 reject
函数。
¥The resolve
and reject
callbacks are only available within the scope of the executor function, which means you can't access them after the promise is constructed. If you want to construct the promise before deciding how to resolve it, you can use the Promise.withResolvers()
method instead, which exposes the resolve
and reject
functions.
解析函数
¥The resolve function
resolve
函数具有以下行为:
¥The resolve
function has the following behaviors:
- 如果使用与新创建的 Promise 相同的值来调用它(Promise 是 "拴在"),则 Promise 将被拒绝并显示
TypeError
。 - 如果使用非 thenable 值(基元或
then
属性不可调用的对象,包括该属性不存在时)调用它,则立即使用该值实现承诺。 - 如果使用 thenable 值(包括另一个
Promise
实例)调用它,则 thenable 的then
方法将被保存并在将来调用(它总是异步调用)。then
方法将通过两个回调进行调用,这两个回调是两个新函数,其行为与传递给executor
函数的resolveFunc
和rejectFunc
完全相同。如果调用then
方法抛出异常,则当前的 Promise 将被拒绝并抛出错误。
在最后一种情况下,它意味着如下代码:
¥In the last case, it means code like:
new Promise((resolve, reject) => {
resolve(thenable);
});
大致相当于:
¥Is roughly equivalent to:
new Promise((resolve, reject) => {
try {
thenable.then(
(value) => resolve(value),
(reason) => reject(reason),
);
} catch (e) {
reject(e);
}
});
除了 resolve(thenable)
案例之外:
¥Except that in the resolve(thenable)
case:
resolve
是同步调用的,因此即使尚未调用通过anotherPromise.then()
附加的处理程序,再次调用resolve
或reject
也不会产生任何效果。then
方法是异步调用的,因此如果传递了 thenable,则 Promise 永远不会立即得到解决。
因为 resolve
被再次调用,无论 thenable.then()
作为 value
传递给它,解析器函数能够展平嵌套的 thenable,其中一个 thenable 用另一个 thenable 调用它的 onFulfilled
处理程序。结果是,真实 Promise 的履行处理程序永远不会收到 thenable 作为其履行值。
¥Because resolve
is called again with whatever thenable.then()
passes to it as value
, the resolver function is able to flatten nested thenables, where a thenable calls its onFulfilled
handler with another thenable. The effect is that the fulfillment handler of a real promise will never receive a thenable as its fulfillment value.
示例
将基于回调的 API 转变为基于 Promise 的 API
¥Turning a callback-based API into a promise-based one
要为函数提供 Promise 功能,请让它通过在正确的时间调用 resolve
和 reject
函数来返回 Promise。
¥To provide a function with promise functionality, have it return a promise by calling the resolve
and reject
functions at the correct times.
function myAsyncFunction(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = () => resolve(xhr.responseText);
xhr.onerror = () => reject(xhr.statusText);
xhr.send();
});
}
调用 resolveFunc 的效果
¥Effect of calling resolveFunc
调用 resolveFunc
会导致 Promise 被解析,因此再次调用 resolveFunc
或 rejectFunc
不会产生任何效果。但是,该承诺可能位于以下任何州:待定、已完成或已拒绝。
¥Calling resolveFunc
causes the promise to become resolved, so that calling resolveFunc
or rejectFunc
again has no effect. However, the promise may be in any of the states: pending, fulfilled, or rejected.
这个 pendingResolved
Promise 在它创建的时候就被解决了,因为它已经是 "锁定" 来匹配内部 Promise 的最终状态,并且调用 resolveOuter
或 rejectOuter
或者稍后在执行器中抛出错误对其最终状态没有影响。然而,内部 Promise 直到 100 毫秒后仍然处于等待状态,因此外部 Promise 也处于等待状态:
¥This pendingResolved
promise is resolved the time it's created, because it has already been "locked in" to match the eventual state of the inner promise, and calling resolveOuter
or rejectOuter
or throwing an error later in the executor has no effect on its eventual state. However, the inner promise is still pending until 100ms later, so the outer promise is also pending:
const pendingResolved = new Promise((resolveOuter, rejectOuter) => {
resolveOuter(
new Promise((resolveInner) => {
setTimeout(() => {
resolveInner("inner");
}, 100);
}),
);
});
这个 fulfilledResolved
承诺在它被解决的那一刻就得到了履行,因为它是用一个非 thenable 值来解决的。然而,当它被创建时,它是未解决的,因为 resolve
和 reject
都还没有被调用。未解决的承诺必然是悬而未决的:
¥This fulfilledResolved
promise becomes fulfilled the moment it's resolved, because it's resolved with a non-thenable value. However, when it's created, it's unresolved, because neither resolve
nor reject
has been called yet. An unresolved promise is necessarily pending:
const fulfilledResolved = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("outer");
}, 100);
});
调用 rejectFunc
显然会导致承诺被拒绝。然而,还有两种方法可以导致即使调用了 resolveFunc
回调,promise 也会立即被拒绝。
¥Calling rejectFunc
obviously causes the promise to reject. However, there are also two ways to cause the promise to instantly become rejected even when the resolveFunc
callback is called.
// 1. Resolving with the promise itself
const rejectedResolved1 = new Promise((resolve) => {
// Note: resolve has to be called asynchronously,
// so that the rejectedResolved1 variable is initialized
setTimeout(() => resolve(rejectedResolved1)); // TypeError: Chaining cycle detected for promise #<Promise>
});
// 2. Resolving with an object which throws when accessing the `then` property
const rejectedResolved2 = new Promise((resolve) => {
resolve({
get then() {
throw new Error("Can't get then property");
},
});
});
规范
Specification |
---|
ECMAScript Language Specification # sec-promise-constructor |
浏览器兼容性
BCD tables only load in the browser