JavaScript创建Promise

原文:JavaScript Create Promise

本文简述JavaScript创建Promise的几种方式。

总的来说,JavaScript有4种方式创建Promise:

Promise构造器

Promise的构造器只接收一个参数——executor函数。当调用new Promise(executor)时,JavaScript会立即执行executor函数,传入2个参数:resolve()reject()

1
2
3
4
5
6
function executor(resolve, reject) {
typeof resolve; // 'function'
typeof reject; // 'function'
}

new Promise(executor);

executor()函数的作用,可以调用resolve()将Promise标记为fulfilled(成功),或调用reject()标记为rejected(失败)。

1
2
3
4
5
6
7
8
9
10
11
12
13
const success = new Promise(function executor(resolve) {
resolve('OK');
});

const fail = new Promise(function executor(resolve, reject) {
reject(new Error('Oops'));
});

const str = await success;
str; // 'OK'

const err = await fail.catch(err => err);
err.message; // Oops

静态函数

Promise.resolve()函数可以创建一个Promise,随后立即变为fulfilled。

1
2
3
4
const p = Promise.resolve(42);
p.then(v => {
v; // 42
});

可以认为Promise.resolve(v)new Promise(resolve => resolve(v))的简写。

类似的,Promise.reject()函数可以创建一个立即标记为rejected的Promise。

1
2
3
4
const p = Promise.reject(new Error('Oops!'));
p.catch(err => {
err.message; // 'Oops!'
});

Promise.reject()时要小心:如果没有在其后加上.catch(),会发生“未处理的Promise异常”。

then()和catch()

在调用.then().catch()时,JavaScript会创建一个新的Promise。

1
2
3
4
5
6
const p = Promise.resolve('Hello');

const p2 = p.then(str => `${str} World`);

p2 instanceof Promise; // true
p2 === p; // false

async函数

在调用async函数时,JavaScript会返回一个新的Promise。无论async函数中返回的是什么,JavaScript都会返回一个Promise,一定要在async函数调用时加上await

1
2
3
4
5
async function test() {
return 42;
}

test() instanceof Promise; // true

不立即执行

JavaScript的Promise在创建时会立即执行executor函数,从这个角度来看,Promise是“热启动”的。

如果你需要一个“冷启动”的Promise,在创建时不执行,直到用await时才执行,那么你应该使用async函数。每次调用一个async函数都会返回一个新的Promise。

1
2
3
4
5
6
7
8
9
10
async function getAnswer() {
return 42;
}

const p1 = getAnswer();
p1 instanceof Promise; // true

const p2 = getAnswer();
p2 instanceof Promise; // true
p2 === p1; // false

另一种常见方式是延迟模式,可以创建一个Promise,但是在executor函数之外调用resolve()reject()函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Promise.deferred = function() {
let resolve = null;
let reject = null;
const p = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
return Object.assign(p, { resolve, reject });
};

const p = Promise.deferred();

p.then(v => {
v; // 42
});

p.resolve(42);

然而延迟模式是一种反模式,因为executor函数之外发生的同步错误,不会把Promise标记为rejected!

1
2
3
4
5
6
7
8
9
10
11
// JavaScript会捕获Promise的executor中发生的任何错误
// 并将Promise标记为rejected
const p1 = new Promise(() => { throw new Error('Oops!'); });
p1.catch(err => {
err.message; // 'Oops!'
});

// 用延迟模式,在executor外部你必须自己处理错误
// 如果你忘记处理错误,Promise会像p2一样永远保持pending状态
const p2 = Promise.deferred();
throw new Error('Oops!');