Promise

Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。

描述

异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

一个 Promise 必然处于以下几种状态之一:

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled): 意味着操作成功完成。
  • 已拒绝(rejected): 意味着操作失败。

因为 Promise.prototype.thenPromise.prototype.catch 方法返回的是 promise, 所以它们可以被链式调用。

方法

Promise.resolve()

1
Promise.resolve(value);

描述

静态方法 Promise.resolve返回一个解析过的Promise对象。

参数

value

将被Promise对象解析的参数,也可以是一个Promise对象,或者是一个thenable。

返回值

返回一个带着给定值解析过的Promise对象,如果参数本身就是一个Promise对象,则直接返回这个Promise对象。

示例

使用静态Promise.resolve方法
1
2
3
4
5
Promise.resolve("Success").then(function(value) {
console.log(value); // "Success"
}, function(value) {
// 不会被调用
});
resolve一个数组
1
2
3
4
var p = Promise.resolve([1,2,3]);
p.then(function(v) {
console.log(v[0]); // 1
});
resolve另一个promise
1
2
3
4
5
6
7
8
9
10
11
12
var original = Promise.resolve(33);
var cast = Promise.resolve(original);
cast.then(function(value) {
console.log('value: ' + value);
});
console.log('original === cast ? ' + (original === cast));

/*
* 打印顺序如下,这里有一个同步异步先后执行的区别
* original === cast ? true
* value: 33
*/
resolve thenable 并抛出错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// Resolve一个thenable对象
var p1 = Promise.resolve({
then: function(onFulfill, onReject) { onFulfill("fulfilled!"); }
});
console.log(p1 instanceof Promise) // true, 这是一个Promise对象

p1.then(function(v) {
console.log(v); // 输出"fulfilled!"
}, function(e) {
// 不会被调用
});

// Thenable在callback之前抛出异常
// Promise rejects
var thenable = { then: function(resolve) {
throw new TypeError("Throwing");
resolve("Resolving");
}};

var p2 = Promise.resolve(thenable);
p2.then(function(v) {
// 不会被调用
}, function(e) {
console.log(e); // TypeError: Throwing
});

// Thenable在callback之后抛出异常
// Promise resolves
var thenable = { then: function(resolve) {
resolve("Resolving");
throw new TypeError("Throwing");
}};

var p3 = Promise.resolve(thenable);
p3.then(function(v) {
console.log(v); // 输出"Resolving"
}, function(e) {
// 不会被调用
});

Promise.reject()

1
Promise.reject(reason);

描述

静态函数Promise.reject返回一个被拒绝的Promise对象。通过使用Error的实例获取错误原因reason对调试和选择性错误捕捉很有帮助。

参数

reason

表示Promise被拒绝的原因。

返回值

一个给定原因了的被拒绝的 Promise

示例

使用静态Promise.reject()方法
1
2
3
4
5
Promise.reject(new Error('fail')).then(function() {
// not called
}, function(error) {
console.error(error); // Stacktrace
});

Promise.prototype.then()

1
2
3
4
5
6
7
p.then(onFulfilled[, onRejected]);

p.then(value => {
// fulfillment
}, reason => {
// rejection
});

描述

由于 thenPromise.prototype.catch() 方法都会返回 promise,它们可以被链式调用——这同时也是一种被称为复合composition) 的操作。

参数

onFulfilled 可选

当 Promise 变成接受状态(fulfilled)时调用的函数。该函数有一个参数,即接受的最终结果(the fulfillment value)。如果该参数不是函数,则会在内部被替换为 (x) => x,即原样返回 promise 最终结果的函数

onRejected 可选

当 Promise 变成拒绝状态(rejected)时调用的函数。该函数有一个参数,即拒绝的原因(rejection reason)。 如果该参数不是函数,则会在内部被替换为一个 “Thrower” 函数 (it throws an error it received as argument)。

返回值

当一个 Promise 完成(fulfilled)或者失败(rejected)时,返回函数将被异步调用(由当前的线程循环来调度完成)。具体的返回值依据以下规则返回。如果 then 中的回调函数:

  • 返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
  • 没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined
  • 抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
  • 返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
  • 返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
  • 返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。

示例

使用then方法
1
2
3
4
5
6
7
8
9
10
11
var p1 = new Promise((resolve, reject) => {
resolve('成功!');
// or
// reject(new Error("出错了!"));
});

p1.then(value => {
console.log(value); // 成功!
}, reason => {
console.error(reason); // 出错了!
});
链式调用

then 方法返回一个 Promise 对象,其允许方法链。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Promise.resolve("foo")
// 1. 接收 "foo" 并与 "bar" 拼接,并将其结果做为下一个 resolve 返回。
.then(function(string) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
string += 'bar';
resolve(string);
}, 1);
});
})
// 2. 接收 "foobar", 放入一个异步函数中处理该字符串
// 并将其打印到控制台中, 但是不将处理后的字符串返回到下一个。
.then(function(string) {
setTimeout(function() {
string += 'baz';
console.log(string);
}, 1)
return string;
})
// 3. 打印本节中代码将如何运行的帮助消息,
// 字符串实际上是由上一个回调函数之前的那块异步代码处理的。
.then(function(string) {
console.log("Last Then: oops... didn't bother to instantiate and return " +
"a promise in the prior then so the sequence may be a bit " +
"surprising");

// 注意 `string` 这时不会存在 'baz'。
// 因为这是发生在我们通过setTimeout模拟的异步函数中。
console.log(string);
});

// logs, in order:
// Last Then: oops... didn't bother to instantiate and return a promise in the prior then so the sequence may be a bit surprising
// foobar
// foobarbaz

Promise.prototype.catch()

1
2
3
4
5
p.catch(onRejected);

p.catch(function(reason) {
// 拒绝
});

描述

catch 方法可以用于您的promise组合中的错误处理。

参数

onRejected

当Promise 被rejected时,被调用的一个Function。 该函数拥有一个参数:reason rejection 的原因。如果 onRejected 抛出一个错误或返回一个本身失败的 Promise , 通过 catch() 返回的Promise 被rejected;否则,它将显示为成功(resolved)。

返回值

一个Promise

示例

捕获抛出的错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 抛出一个错误,大多数时候将调用catch方法
var p1 = new Promise(function(resolve, reject) {
throw 'Uh-oh!';
});

p1.catch(function(e) {
console.log(e); // "Uh-oh!"
});

// 在异步函数中抛出的错误不会被catch捕获到
var p2 = new Promise(function(resolve, reject) {
setTimeout(function() {
throw 'Uncaught Exception!';
}, 1000);
});

p2.catch(function(e) {
console.log(e); // 不会执行
});

// 在resolve()后面抛出的错误会被忽略
var p3 = new Promise(function(resolve, reject) {
resolve();
throw 'Silenced Exception!';
});

p3.catch(function(e) {
console.log(e); // 不会执行
});
如果已决议
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//创建一个新的 Promise ,且已决议
var p1 = Promise.resolve("calling next");

var p2 = p1.catch(function (reason) {
//这个方法永远不会调用
console.log("catch p1!");
console.log(reason);
});

p2.then(function (value) {
console.log("next promise's onFulfilled"); /* next promise's onFulfilled */
console.log(value); /* calling next */
}, function (reason) {
console.log("next promise's onRejected");
console.log(reason);
});

Promise.all()

1
Promise.all(iterable);

描述

此方法在集合多个 promise 的返回结果时很有用。

  • 完成(Fulfillment):
    如果传入的可迭代对象为空,Promise.all 会同步地返回一个已完成(resolved)状态的promise
    如果所有传入的 promise 都变为完成状态,或者传入的可迭代对象内没有 promisePromise.all 返回的 promise 异步地变为完成。
    在任何情况下,Promise.all 返回的 promise 的完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值)。

  • 失败/拒绝(Rejection):
    如果传入的 promise 中有一个失败(rejected),Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成。

参数

iterable

一个可迭代对象,如 ArrayString

返回值

  • 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promise
  • 如果传入的参数不包含任何 promise,则返回一个异步完成(asynchronously resolved) Promise。注意:Google Chrome 58 在这种情况下返回一个已完成(already resolved)状态的 Promise
  • 其它情况下返回一个处理中(pending)Promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成或失败。 见下方关于“Promise.all 的异步或同步”示例。返回值将会按照参数内的 promise 顺序排列,而不是由调用 promise 的完成顺序决定。

示例

Promise.all 的使用
1
2
3
4
5
6
7
8
9
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});

Promise.all([p1, p2, p3]).then(values => {
console.log(values); // [3, 1337, "foo"]
});
Promise.all 的异步和同步
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// we are passing as argument an array of promises that are already resolved,
// to trigger Promise.all as soon as possible
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.all(resolvedPromisesArray);
// immediately logging the value of p
console.log(p);

// using setTimeout we can execute code after the stack is empty
setTimeout(function(){
console.log('the stack is now empty');
console.log(p);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

如果 Promise.all 失败,也是一样的:

1
2
3
4
5
6
7
8
9
10
11
12
var mixedPromisesArray = [Promise.resolve(33), Promise.reject(44)];
var p = Promise.all(mixedPromisesArray);
console.log(p);
setTimeout(function(){
console.log('the stack is now empty');
console.log(p);
});

// logs
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "rejected", <reason>: 44 }

但是,Promise.all 当且仅当传入的可迭代对象为空时为同步:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);
console.log(p2)
setTimeout(function(){
console.log('the stack is now empty');
console.log(p2);
});

// logs
// Promise { <state>: "fulfilled", <value>: Array[0] }
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

Promise.any()

1
Promise.any(iterable);

描述

这个方法用于返回第一个成功的 promise 。只要有一个 promise 成功此方法就会终止,它不会等待其他的 promise 全部完成。

不像 Promise.all() 会返回一组完成值那样(resolved values),我们只能得到一个成功值(假设至少有一个 promise 完成)。当我们只需要一个 promise 成功,而不关心是哪一个成功时此方法很有用的。

同时, 也不像 Promise.race() 总是返回第一个结果值(resolved/reject)那样,这个方法返回的是第一个 成功的 值。这个方法将会忽略掉所有被拒绝的 promise,直到第一个 promise 成功。

参数

iterable

一个可迭代的对象, 例如 Array

返回值

  • 如果传入的参数是一个空的可迭代对象,则返回一个 已失败(already rejected) 状态的 Promise
  • 如果传入的参数不包含任何 promise,则返回一个 异步完成asynchronously resolved)的 Promise
  • 其他情况下都会返回一个处理中(pending)Promise。 只要传入的迭代对象中的任何一个 promise 变成成功(resolve)状态,或者其中的所有的 promises 都失败,那么返回的 promise 就会 异步地(当调用栈为空时) 变成成功/失败(resolved/reject)状态。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const pErr = new Promise((resolve, reject) => {
reject("总是失败");
});

const pSlow = new Promise((resolve, reject) => {
setTimeout(resolve, 500, "最终完成");
});

const pFast = new Promise((resolve, reject) => {
setTimeout(resolve, 100, "很快完成");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
console.log(value);
// pFast fulfils first
})
// 期望输出: "很快完成"
显示第一张已加载的图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function fetchAndDecode(url) {
return fetch(url).then(response => {
if(!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
} else {
return response.blob();
}
})
}

let coffee = fetchAndDecode('coffee.jpg');
let tea = fetchAndDecode('tea.jpg');

Promise.any([coffee, tea]).then(value => {
let objectURL = URL.createObjectURL(value);
let image = document.createElement('img');
image.src = objectURL;
document.body.appendChild(image);
})
.catch(e => {
console.log(e.message);
});

Promise.race()

1
Promise.race(iterable);

描述

race 函数返回一个 Promise,它将与第一个传递的 promise 相同的完成方式被完成。它可以是完成( resolves),也可以是失败(rejects),这要取决于第一个完成的方式是两个中的哪个。

如果传的迭代是空的,则返回的 promise 将永远等待。

如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则 Promise.race 将解析为迭代中找到的第一个值。

参数

iterable

可迭代对象,类似Array。详见 iterable

返回值

一个待定的 Promise 只要给定的迭代中的一个promise解决或拒绝,就采用第一个promise的值作为它的值,从而异步地解析或拒绝(一旦堆栈为空)。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// we are passing as argument an array of promises that are already resolved,
// to trigger Promise.race as soon as possible
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.race(resolvedPromisesArray);
// immediately logging the value of p
console.log(p);

// using setTimeout we can execute code after the stack is empty
setTimeout(function(){
console.log('the stack is now empty');
console.log(p);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: 33 }