Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。
当我们需要给予调用者一个承诺:待会儿我会给你回调数据时,就可以创建一个Promise的对象;
Promise的三个状态
- 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
- 已兑现(fulfilled): 意味着操作成功完成。
- 已拒绝(rejected): 意味着操作失败。
待定状态的 Promise 对象要么会通过一个值被兑现(fulfilled),要么会通过一个原因(错误)被拒绝(rejected)。
Promise的基本结构
function getData(param) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const b = true;
if (b) {
resolve("success");
} else {
reject("failed");
}
}, 1000);
});
}
executor
这是一个双参函数,参数为resolve
和reject
。Promise
的实现会立即执行executor
,并传入resolve
和reject
函数。当resolve
和reject
函数被调用时,它们分别对promise执行resolve
和reject
。executor
通常会触发一些异步运算,一旦运算成功完成,则resolve
掉这个promise,如果出错则reject
掉。如果executor
函数执行时抛出异常,promise状态会变为rejected
。executor
的返回值也会被忽略。
resove函数调用时,不同值的区别
- 如果resolve传入的是一个普通的值或者对象,那么这个值会作为
then
回调的参数。 ```javascript function getData(param) { return new Promise((resolve, reject) => { setTimeout(() => {
}, 1000); }); }resolve("success");
getData().then((res) => { console.log(res); });
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21450449/1638854335994-7097d7d0-c14f-4fe8-a29e-f968177db33c.png#clientId=u0b1380c5-3d0d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=121&id=u2d932ff1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=121&originWidth=650&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10129&status=done&style=none&taskId=u7b673881-c4e5-4b34-91b8-b9c585e2703&title=&width=650)
- 如果resolve传入的是另一个Promise对象,那么新的Promise对象会决定原Promise的状态。
```javascript
function getData(param) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const newPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("newPromise failed");
}, 2000);
});
resolve(newPromise);
}, 1000);
});
}
getData()
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
- 如果resolve传入的是一个对象,并且该对象中有
then
方法,那么会执行该then方法,并且根据then方法的结果来决定原Promise的状态。 ```javascript function getData(param) { return new Promise((resolve, reject) => { setTimeout(() => {
}, 1000); }); }const obj = { then(resolve, reject) { setTimeout(() => { reject("newPromise failed"); }, 2000); }, }; resolve(obj);
getData() .then((res) => { console.log(res); }) .catch((err) => { console.log(err); });
![image.png](https://cdn.nlark.com/yuque/0/2021/png/21450449/1638854456146-36fc4d56-556a-4e23-854f-3916ff5b59f4.png#clientId=u0b1380c5-3d0d-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=110&id=FA8Ct&margin=%5Bobject%20Object%5D&name=image.png&originHeight=110&originWidth=647&originalType=binary&ratio=1&rotation=0&showTitle=false&size=10372&status=done&style=none&taskId=u551b65ea-f36e-431d-82d9-8d467839141&title=&width=647)
<a name="vGTNp"></a>
#### promise.then()
then方法是Promise对象上的一个方法:它其实是放在`Promise`的原型上的`Promise.prototype.then`。
:::info
then()方法返回一个Promise,它最多需要有两个参数:Promise 的成功和失败情况的回调函数。
:::
**语法:**
```javascript
p.then(onFulfilled[, onRejected]);
p.then(value => {
// fulfillment
}, reason => {
// rejection
});
返回值:
当一个 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 变为终态时的回调函数的参数是相同的。
promise.catch()
catch方法是Promise对象上的一个方法:它其实是放在Promise
的原型上的Promise.prototype.catch
。
由于 then 和Promise.prototype.catch()
方法都会返回 promise,它们可以被链式调用——这同时也是一种被称为复合( composition) 的操作。当一个promise未进行捕获(catch)操作,那么如果executor在执行过程中完成rejected时,会报错。
promise.finally()
finally是在ES9(ES2018)中新增的一个特性:表示无论Promise对象无论变成fulfilled还是reject状态,最终都会 被执行的代码。 :::info finally方法是不接收参数的,因为无论前面是fulfilled状态,还是reject状态,它都会执行。 :::
function getData(param) {
return new Promise((resolve, reject) => {
resolve();
});
}
getData()
.then((res) => {
console.log(res);
})
.finally(() => {
console.log("finally code");
});
Promise的静态方法
Promise.resolve()
Promise.resolve(value)
方法返回一个以给定值解析后的Promise对象。
Promise.resolve("suc").then((res) => {
console.log(res);
});
// 等价于
new Promise((resolve) => {
resolve("suc2");
}).then((res) => {
console.log(res);
});
:::info
Promise.resolve()
方法的参数的三种情况与executor
中resolve
函数调用时的区别一致。
:::
Promise.reject()
Promise.all()
Promise.all()
方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。
const p1 = new Promise((resolve) => {
resolve("res1");
});
const p2 = new Promise((resolve) => {
resolve("res2");
});
const p3 = new Promise((resolve) => {
resolve("res3");
});
Promise.all([p1, p2, p3]).then((res) => {
console.log(res);
});
Promise.allSetted()
Promise.all()
方法有一个缺陷:当有其中一个Promise变成reject状态时,新Promise就会立即变成对应的reject状态。那么对于resolved的,以及依然处于pending状态的Promise,我们是获取不到对应的结果的。
在ES11(ES2020)中,添加了新的API Promise.allSettled
在**Promise.allSettled()**
方法返回一个在所有给定的promise都已经fulfilled
或rejected
后的promise,并带有一个对象数组,每个对象表示对应的promise结果。
const p1 = new Promise((resolve) => {
resolve("res1");
});
const p2 = new Promise((resolve, reject) => {
reject("res2");
});
const p3 = new Promise((resolve) => {
resolve("res3");
});
Promise.allSettled([p1, p2, p3]).then((res) => {
console.log(res);
});
Promise.race()
**Promise.race(iterable)**
方法返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。
Promise.any()
any方法是ES12中新增的方法。**Promise.any()**
接收一个Promise可迭代对象,只要其中的一个 promise
成功,就返回那个已经成功的 promise 。
如果可迭代对象中没有一个 promise 成功(即所有的 promises 都失败/拒绝),就返回一个失败的 promise 和AggregateError
类型的实例,它是 Error
的一个子类,用于把单一的错误集合在一起。
本质上,这个方法和Promise.all()
是相反的。
:::warning
注意! Promise.any()
方法依然是实验性的,尚未被所有的浏览器完全支持。
:::
手写Promise
1. Promise的基本实现
实现最简单的Promise
以及基本调用流程
XPromise.js
const PROMISE_STATUS_PENDING = 0;
const PROMISE_STATUS_FULFILLED = 1;
const PROMISE_STATUS_REJECTED = 2;
class XPromise {
constructor(executor) {
// promise的状态
this.status = PROMISE_STATUS_PENDING;
this.onfulfilled = undefined
this.onRejected = undefined
// resolve函数
this.resolve = (value) => {
queueMicrotask(() => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED;
this.onfulfilled(value);
}
});
};
// reject函数
this.reject = (reason) => {
queueMicrotask(() => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED;
this.onRejected(reason);
}
});
};
// 调用传入的函数,并将resolve和reject函数传入
executor(this.resolve, this.reject);
}
// then方法
then(onfulfilled) {
this.onfulfilled = onfulfilled;
}
// catch方法
catch(onRejected) {
this.onRejected = onRejected;
}
}
export { XPromise };
test.js
import { XPromise } from "./XPromise.js";
function getData() {
return new XPromise((resolve, reject) => {
setTimeout(() => {
resolve("hello");
}, 1000);
});
}
getData().then((res) => {
console.log(res);
});
2.(优化一)——多个then、catch的调用
XPromise.js
const PROMISE_STATUS_PENDING = 0;
const PROMISE_STATUS_FULFILLED = 1;
const PROMISE_STATUS_REJECTED = 2;
class XPromise {
constructor(executor) {
// promise的状态
this.status = PROMISE_STATUS_PENDING;
this.onfulfilledFns = [];
this.onRejectedFns = [];
// resolve函数
this.resolve = (value) => {
queueMicrotask(() => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED;
this.onfulfilledFns.forEach((fn) => {
fn(value);
});
}
});
};
// reject函数
this.reject = (reason) => {
queueMicrotask(() => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED;
this.onRejectedFns.forEach((fn) => {
fn(reason);
});
}
});
};
// 调用传入的函数,并将resolve和reject函数传入
executor(this.resolve, this.reject);
}
// then方法
then(onfulfilled, onRejected) {
if (onfulfilled) {
this.onfulfilledFns.push(onfulfilled);
}
if (onRejected) {
this.onRejectedFns.push(onRejected);
}
}
// catch方法
catch(onRejected) {
if (onRejected) {
this.onRejectedFns.push(onRejected);
}
}
}
export { XPromise };
test.js
import { XPromise } from "./XPromise.js";
function getData() {
return new XPromise((resolve, reject) => {
setTimeout(() => {
resolve("hello");
}, 1000);
});
}
const p = getData();
p.then((res) => {
console.log("then1", res);
});
p.then((res) => {
console.log("then2", res);
});
p.catch((reason) => {
console.log(reason);
});
3*.(优化二)——链式调用及异常处理
XPromise.js
const PROMISE_STATUS_PENDING = 0;
const PROMISE_STATUS_FULFILLED = 1;
const PROMISE_STATUS_REJECTED = 2;
/**
* 生成一个携带resolve和reject的回调函数
*/
function generatorFn(callBack, resolve, reject) {
return (value) => {
try {
const res = callBack(value);
resolve(res);
} catch (error) {
reject(error);
}
};
}
class XPromise {
constructor(executor) {
// promise的状态
this.status = PROMISE_STATUS_PENDING;
this.onfulfilledFns = [];
this.onRejectedFns = [];
// resolve函数
this.resolve = (value) => {
queueMicrotask(() => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_FULFILLED;
this.onfulfilledFns.forEach((fn) => {
fn(value);
});
}
});
};
// reject函数
this.reject = (reason) => {
queueMicrotask(() => {
if (this.status === PROMISE_STATUS_PENDING) {
this.status = PROMISE_STATUS_REJECTED;
this.onRejectedFns.forEach((fn) => {
fn(reason);
});
}
});
};
// 调用传入的函数,并将resolve和reject函数传入
executor(this.resolve, this.reject);
}
// then方法
then(onfulfilled, onRejected) {
onfulfilled = onfulfilled ?? ((value) => value);
// (重要)如果onRejected没有值,赋值为抛出异常,一直扔给下一个promise去处理
const errFn = (err) => {
throw err;
};
onRejected = onRejected ?? errFn;
return new XPromise((resolve, reject) => {
const fulfilledFn = generatorFn(onfulfilled, resolve, reject);
this.onfulfilledFns.push(fulfilledFn);
const rejectedFn = generatorFn(onRejected, resolve, reject);
this.onRejectedFns.push(rejectedFn);
});
}
// catch方法
catch(onRejected) {
return new XPromise((resolve, reject) => {
if (onRejected) {
const fn = generatorFn(onRejected, resolve, reject);
this.onRejectedFns.push(fn);
}
});
}
}
export { XPromise };
test.js
import { XPromise } from "./XPromise.js";
function getData() {
return new XPromise((resolve, reject) => {
setTimeout(() => {
resolve("hello");
}, 1000);
});
}
const p = getData();
p.then((res) => {
console.log("res1", res);
throw new Error("test error");
console.log("next code");
})
.then((res) => {
console.log("res2", res);
})
.then((res) => {
console.log("res2", res);
})
.then((res) => {
console.log("res2", res);
})
.catch((err) => {
console.log(err);
});
4.(优化三)——在Promise已经敲定状态下then()和catch()的处理
// ...
class XPromise {
// ...
// then方法
then(onfulfilled, onRejected) {
onfulfilled = onfulfilled ?? ((value) => value);
// 如果onRejected没有值,赋值为抛出异常,一直扔给下一个promise去处理
const errFn = (err) => {
throw err;
};
onRejected = onRejected ?? errFn;
return new XPromise((resolve, reject) => {
// 判断该Promise的状态
switch (this.status) {
case PROMISE_STATUS_FULFILLED:
// 直接执行
generatorFn(onfulfilled, resolve, reject)(this.value);
break;
case PROMISE_STATUS_REJECTED:
// 直接执行
generatorFn(onRejected, resolve, reject)(this.reason);
break;
default:
const fulfilledFn = generatorFn(onfulfilled, resolve, reject);
this.onfulfilledFns.push(fulfilledFn);
const rejectedFn = generatorFn(onRejected, resolve, reject);
this.onRejectedFns.push(rejectedFn);
}
});
}
// catch方法
catch(onRejected) {
return new XPromise((resolve, reject) => {
if (onRejected) {
switch (this.status) {
case PROMISE_STATUS_REJECTED:
// 直接执行
generatorFn(onRejected, resolve, reject)(this.reason);
break;
case PROMISE_STATUS_PENDING:
const fn = generatorFn(onRejected, resolve, reject);
this.onRejectedFns.push(fn);
}
}
});
}
}
export { XPromise };
5.(补充)finally方法的实现
直接调用then()
class XPromise {
// ...
finally(onFinally) {
return this.then(
() => {
onFinally();
return this.value;
},
() => {
onFinally();
throw this.reason;
}
);
}
}
6. (补充)Promise.resolve()及Promise.reject()
class XPromise {
// ...
static resolve(param) {
return new XPromise((resolve, reject) => {
resolve(param);
});
}
static reject(reason) {
return new XPromise((resolve, reject) => {
reject(reason);
})
}
}
7.(补充)Promise.all()
class XPromise {
// ...
static all(xPromises) {
return new XPromise((resolve, reject) => {
const results = [];
xPromises.forEach((p) => {
p.then(
(res) => {
results.push(res);
if (results.length === xPromises.length) {
resolve(results);
}
},
(err) => {
reject(err);
}
);
});
});
}
}
8.(补充)Promise.allSetted()
class XPromise {
// ...
static allSetted(xPromises) {
return new XPromise((resolve, reject) => {
const results = [];
xPromises.forEach((p) => {
p.then(
(res) => {
results.push({
status: "fulfilled",
value: res,
});
if (results.length === xPromises.length) {
resolve(results);
}
},
(err) => {
results.push({
status: "rejected",
reason: err,
});
if (results.length === xPromises.length) {
resolve(results);
}
}
);
});
});
}
}
9.(补充)Promise.race()
class XPromise {
// ...
static race(xPromises) {
return new XPromise((resolve, reject) => {
xPromises.forEach((p) => {
p.then(
(res) => resolve(res),
(err) => reject(err)
);
});
});
}
}
10.(补充)Promise.any()
与Promise.all()
相反
class XPromise {
// ...
static all(xPromises) {
return new XPromise((resolve, reject) => {
const results = [];
xPromises.forEach((p) => {
p.then(
(res) => {
resolve(res)
},
(err) => {
results.push(res);
if (results.length === xPromises.length) {
reject(results);
}
}
);
});
});
}
}