今日无事,勾栏听....
呸呸呸,今日无事,复习一下Promise吧
嘿,各位前端大佬们!今天咱们来复习下JavaScript里的Promise。Promise就像是咱们生活中的一个承诺,要么兑现(成功),要么食言(失败),而且一旦有了结果,就不会再改变啦。就好比你跟朋友约好一起吃饭,要么按时赴约(成功),要么放鸽子(失败),不会出现又赴约又放鸽子这种奇葩情况哈。
一、Promise的基本结构
咱们先来看一下Promise的基本结构,它是一个构造函数,接受一个执行器函数executor
作为参数。这个执行器函数有两个参数,分别是resolve
和reject
。
class Promise {
constructor(executor) {
// 状态,一开始是pending(等待中)
this.PromiseState = "pending";
// 结果,初始为null
this.PromiseResult = null;
// 回调函数数组,用来存放后续的回调
this.callbacks = [];
const self = this;
// 成功函数
function resolve(value) {
// 如果状态不是pending,就直接返回,因为Promise的状态一旦改变就不能再变啦
if (self.PromiseState !== "pending") return;
// 状态变为fulfilled(已成功)
self.PromiseState = "fulfilled";
// 保存成功的结果
self.PromiseResult = value;
// 如果有回调函数,就用setTimeout异步执行它们
if (self.callbacks.length) {
setTimeout(() => {
self.callbacks.forEach((item) => {
item.onResolved(value);
});
});
}
}
// 失败函数
function reject(value) {
// 同样,如果状态不是pending,直接返回
if (self.PromiseState !== "pending") return;
// 状态变为rejected(已失败)
self.PromiseState = "rejected";
// 保存失败的结果
self.PromiseResult = value;
// 如果有回调函数,异步执行它们
if (self.callbacks.length) {
setTimeout(() => {
self.callbacks.forEach((item) => {
item.onRejected(value);
});
});
}
}
// 同步调用执行器函数,如果执行器函数报错,就调用reject
try {
executor(resolve, reject);
} catch (err) {
reject(err);
}
}
}
这里面有几个关键点哈:
PromiseState
:表示Promise的状态,有三种可能:pending
(等待中)、fulfilled
(已成功)、rejected
(已失败)。PromiseResult
:用来保存Promise的结果,不管是成功的结果还是失败的原因。callbacks
:一个数组,用来存放后续的回调函数。因为Promise可以链式调用,所以可能会有多个回调函数。resolve
和reject
:这两个函数是用来改变Promise状态的。resolve
把状态变为fulfilled
,reject
把状态变为rejected
。
二、Promise的then方法
then
方法是Promise最常用的方法之一,它用来处理Promise的结果。then
方法接受两个参数,分别是onResolved
和onRejected
,这两个参数都是函数。onResolved
用来处理成功的结果,onRejected
用来处理失败的原因。
Promise.prototype.then = function (onResolved, onRejected) {
const self = this;
// 如果onRejected不是函数,就给它一个默认的函数,这个函数会抛出错误
if (typeof onRejected !== "function") {
onRejected = (reason) => {
throw reason;
};
}
// 如果onResolved不是函数,就给它一个默认的函数,这个函数会返回传入的值
if (typeof onResolved !== "function") {
onResolved = (value) => {
return value;
};
}
return new Promise((resolve, reject) => {
// 封装一个回调函数
function callback(type) {
try {
// 执行传入的函数,得到结果
const result = type(self.PromiseResult);
// 如果结果是一个Promise,就调用它的then方法,根据结果调用resolve或reject
if (result instanceof Promise) {
result.then(
(r) => {
resolve(r);
},
(reason) => {
reject(reason);
}
);
} else {
// 如果结果不是Promise,就直接调用resolve
resolve(result);
}
} catch (error) {
// 如果执行过程中报错,就调用reject
reject(error);
}
}
// 如果Promise的状态是fulfilled,就异步调用callback函数
if (this.PromiseState === "fulfilled") {
setTimeout(() => {
callback(onResolved);
});
}
// 如果Promise的状态是rejected,就异步调用callback函数
if (this.PromiseState === "rejected") {
setTimeout(() => {
callback(onRejected);
});
}
// 如果Promise的状态是pending,就把回调函数保存起来
if (this.PromiseState === "pending") {
this.callbacks.push({
onResolved: function () {
callback(onResolved);
},
onRejected: function () {
callback(onRejected);
},
});
}
});
};
then
方法的关键点:
- 返回一个新的Promise:这样就可以实现链式调用啦。
- 处理不同状态:根据Promise的状态,决定是立即执行回调函数还是保存回调函数。
- 处理返回值:如果回调函数的返回值是一个Promise,就等待这个Promise的结果,再决定新Promise的状态。
三、Promise的其他方法
1. catch方法
catch
方法其实就是then
方法的一个语法糖,它只接受一个参数onRejected
,用来处理Promise的失败情况。
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected);
};
2. resolve方法
resolve
方法是一个静态方法,它可以把一个值或者一个Promise转换成一个Promise。
Promise.resolve = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(
(v) => resolve(v),
(r) => reject(r)
);
} else {
resolve(value);
}
});
};
3. reject方法
reject
方法也是一个静态方法,它可以把一个值或者一个Promise转换成一个被拒绝的Promise。
Promise.reject = function (value) {
return new Promise((resolve, reject) => {
if (value instanceof Promise) {
value.then(
(v) => reject(v),
(r) => reject(r)
);
} else {
reject(value);
}
});
};
4. all方法
all
方法接受一个Promise数组作为参数,返回一个新的Promise。只有当数组中的所有Promise都成功时,新的Promise才会成功,返回值是一个数组,包含所有Promise的结果。如果有一个Promise失败,新的Promise就会失败,返回失败的原因。
Promise.all = function (promises) {
return new Promise((resolve, reject) => {
let fulfilledCount = 0;
let arr = [];
let rejected = false;
for (let i = 0; i < promises.length; i++) {
if (rejected) break;
const promise = promises[i];
if (promise instanceof Promise) {
promise.then(
(v) => {
fulfilledCount++;
arr[i] = v;
if (promises.length === fulfilledCount) {
resolve(arr);
}
},
(r) => {
rejected = true;
reject(r);
}
);
} else {
fulfilledCount++;
arr[i] = promise;
}
}
});
};
5. race方法
race
方法也接受一个Promise数组作为参数,返回一个新的Promise。只要数组中的有一个Promise有了结果(不管是成功还是失败),新的Promise就会有相同的结果。
Promise.race = function (promises) {
return new Promise((resolve, reject) => {
let resolved = false;
let rejected = false;
for (let i = 0; i < promises.length; i++) {
if (resolved || rejected) break;
const promise = promises[i];
if (promise instanceof Promise) {
promise.then(
(v) => {
resolved = true;
resolve(v);
},
(r) => {
rejected = true;
reject(r);
}
);
} else {
resolve(promise);
break;
}
}
});
};
四、关键点
- Promise的状态是不可变的:一旦Promise的状态变为
fulfilled
或rejected
,就不能再改变了。这是Promise的一个重要特性,保证了结果的确定性。 - then方法返回的是一个新的Promise:这样就可以实现链式调用,每个
then
方法都可以处理上一个Promise的结果。 - catch方法可以捕获前面的错误:如果Promise链中有一个Promise失败了,后面的
catch
方法可以捕获这个错误。 - resolve和reject方法是静态方法:可以直接通过
Promise.resolve()
和Promise.reject()
来使用。 - all方法需要所有Promise都成功才会成功:只要有一个Promise失败,整个
Promise.all
就会失败。 - race方法只要有一个Promise有结果就会有结果:不管是成功还是失败,只要有一个Promise有了结果,
Promise.race
就会有相同的结果。 - Promise的回调函数是异步执行的:使用
setTimeout
来保证回调函数是异步执行的,避免了回调地狱。 - then方法的参数可以省略:如果只关心成功或失败的情况,可以只传一个参数给
then
方法。 - Promise可以链式调用多个then方法:每个
then
方法都可以处理上一个Promise的结果。 - Promise可以处理异步操作:比如网络请求、文件读取等,把异步操作封装成Promise,就可以用链式调用的方式来处理结果。
好啦,关于 Promise 就写到这里啦!希望这篇博客能让你对 Promise 有更深入的理解。如果有什么问题,那就多看几遍吧。所谓书读百遍其义自现。