原文地址:Promises In Javascriptundefined日期:2019-04-14
在 Javascript 中,Promise 是一种用作最初未知的数据特殊的对象。
这个概念并不是 Javascript 特有的,其他语言中也存在类似的结构。
它们在 Java、Python、Lisp、C++及其他不同语言中有不同的名字,例如features
、deferreds
、delays
等等。
Promise一词由 Daniel P. Friedman 和 David Wise 在1976年名为《应用程序设计对多处理的影响》的论文中首次提出。
Promise
在JavaScript
用于处理异步操作的结果。
例如下面这段代码中,我们使用 callback 来执行异步操作。
setTimeout(() => {
console.log("Async operation.");
}, 1000);
我们可以使Promise重构这段代码。
const promiseSetTimeout = ms => new Promise(resolve => setTimeout(resolve, ms));
promiseSetTimeout(1000).then(() => console.log("Async operation"));
这里我们使用Promise
实例的then
方法在Promise
被解决后执行操作。
在 ES6
中也可以使用 async/await
语法来处理Promise
const promiseSetTimeout = ms => new Promise(resolve => setTimeout(resolve, ms));
await promiseSetTimeout(1000)
console.log("Async operation");
// 1000ms 后被执行
Promise 存在三种不同的状态:
Promise
的状态只能改变一次,即从Pending
到Resolved/Rejected
,并且不能再次改变为Pending
。
Promise
实例化接受一个函数为参数,如下例中executor
,在实例化Promise
之后会立即执行executor
函数。
const promise = new Promise(executor);
executor 函数接受两个参数,分别为 resolve
和 reject
const promise = new Promise((resolve, reject) => {
resolve("Async success!");
});
调用resolve
后会将Promise
的状态转换为 resolved
。在调用成功后,可以通过Promise
实例中的then
方法来获取执行的结果。
promise.then(result => console.log(result));
当然也可以在executor
中调用reject
。
const promise = new Promise((resolve, reject) => {
reject("Async failed!");
});
这样的话,Promise
的状态将会变为rejected
。Promise
中也提供了catch
方法来处理这种状态。
译者注:如果没有通过注册过
rejected
的callback
,会导致Promise
内部抛出一个未捕获的错误。
promise.catch(result => console.log(result));
Promise
实例中也提供了finally
方法,不论Promise
的状态转换为resolved
还是rejected
都会执行该方法。
promise.finally(result => console.log(result));
译者注:
then
方法可以同时接收两个参数,finally
更像是then
方法的语法糖。
then
和catch
都会返回一个Promise
实例,所以我们可以得到一种链式的写法。
new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
})
.then(result => {
console.log(result); // 1
return result + 1;
})
.then(result => {
console.log(result); // 2
return result + 1;
})
.then(result => {
console.log(result); // 3
return result + 1;
});
在上面的例子中,每次调用then
方法都会返回一个新的Promise
,我们可以在then
方法之后再次调用其返回的Promise
的then
方法,所以,后面的callback
只能在上一个Promise
变为resolved
之后被依次执行。
同样的,我们可以使用then
为同一个 Promise 增加多个回调,但是这样我们就不能链式调用了。
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
promise.then(result => {
console.log(result); // 1
return result + 1;
});
promise.then(result => {
console.log(result); // 1
return result + 1;
});
promise.then(result => {
console.log(result); // 1
return result + 1;
});
在上面的例子中,同一个原始Promise
的then
方法的执行相互独立。
译者注:这里相互独立指的是一个
then
的执行结果并不会改变该Promise
的执行结果,同样也不会影响到其他then
方法的执行。
Promise
对象上也提供了静态方法。
当我们需要将已知值作为Promise
返回时使用,该方法返回一个给定值且状态为resolved
的Promise
。
const resolvedPromise = Promise.resolve("Success");
该方法返回一个错误且状态为rejected
的Promise
。
const rejectedPromise = Promise.reject("Failure");
该方法接受一个可迭代的Promise
容器(通常是一个数组)并返回一个新的Promise
,当容器中所有Promise
的状态变为resolved
时该方法返回的Promise
的状态才变为resolved
,并且将所有Promise
的结果通过then
方法返回。
const allPromises = Promise.all([promise1, promise2, promise3]);
then
方法中接收到的结果与容器中的Promise
顺序一致。
Promise.all([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
]).then(console.log); // [1,2,3]
上例中,即使第一个Promise
的状态最后转换为resolved
,其结果仍将是值数组中的第一个。
译者注:容器中只要有一个
Promise
的状态为rejected
,都会导致该方法返回的Promise
被rejected
。
该方法接受一个可迭代的Promise
容器(通常是一个数组)并返回一个新的Promise
,当容器中存在一个Promise
的状态变为resolved/rejected
时该方法返回的Promise
的状态就变为resolved/rejected
,并且将该Promise
的结果/错误通过then/catch
方法返回。
Promise.race([
new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
new Promise(resolve => setTimeout(() => reject(3), 1000)) // 3
]).then(console.log); // 3