Promise
是 JavaScript 中的对异步操作最佳的 API 之一。作为 JavaScript 开发人员,需要熟练掌握 Promise
相关的知识。本文就来总结一下这些知识点,先来回顾 JavaScript 过去异步操作的处理方式?然后详细介绍 Promises 对象及相关的方法。
现在先来了解一下 JavaScript 异步概念。
异步回顾
什么是异步?如果在函数返回的时候,调用者还不能获取到预期结果,而是将来通过一定的方式得到(例如回调函数),这函数就是异步。
异步回调
异步回调,就是常见的 callback
,这是过去在 JavaScript 中处理异步操作的常见方式,如 AJAX ,发起一个 HTTP 请求,具体服务器什么时候返回响应数据取决于客户的环境,存在很多不确定因素,这时采用回调函数可以在返回响应数据的时候触发回调函数。
这种方式当有多个请求的情况,后续请求需要等待前面请求的响应数据的时候,就会出现常见的回调地狱。
const asyncMessage = function (message, callback) {
setTimeout(function () {
console.log(message);
callback();
}, 1000);
};
asyncMessage("title", function () {
asyncMessage("cate", function () {
asyncMessage("content", function () {
console.log("detail");
});
});
});
出现回调地狱将会给项目开发带来很多问题:
-
会导致逻辑混乱,耦合性高,改动一处就会导致全部变动,嵌套多时,BUG 问题难以发现。
-
不能使用
try...catch
来捕获异常。 -
不能使用
return
返回真实数据
为了避免回调地狱的出现,后来就有了 Promise
对象。
Promise 的工作方式
promise
对象是一个可以从异步函数同步返回的对象,它将处于 3 种可能的状态之一:
fulfilled
已兑现: onFulfilled()
将被调用,即操作完成(例如,resolve()
被调用)rejected
已拒绝: onRejected()
将被调用,即操作失败(例如,reject()
被调用)pending
待定:初始状态,既没有被兑现,也没有被拒绝
如果一个 promise
没有挂起(它已被解决或拒绝),它就会被解决。有时使用已解决和已解决表示同一件事:不是 pending
。
promise
一旦确定,就不能再重新确定,再次调用 resolve()
或 reject()
将没有效果。一个已确定的 promise
的具有不可变性。
对于 promise
的状态监控可以使用承诺链,即在 fulfilled
已兑现的状态可以使用 then
方法可以获取已兑现的结果,在rejected
已拒绝状态使用 catch
方法获取拒绝的原因。
const myPromise = new Promise(myExecutorFunc)
.then(handleFulfilledA)
.then(handleFulfilledB)
.then(handleFulfilledC)
.catch(handleRejectedAny);
看起来比 callback
的方式优雅一点,对于需要发起多次 HTTP 请求才能完整呈现的需求,代码如下:
const getPost = () => fetch("https://jsonplaceholder.typicode.com/posts/1");
const getAuthor = (id) =>
fetch("https://jsonplaceholder.typicode.com/users/" + id);
const getComment = (id) =>
fetch("https://jsonplaceholder.typicode.com/users/" + id);
getPost() // #1.fetch post
.then((postResponse) => postResponse.json()) // #2. get & return post json
.then((postResponse) =>
getAuthor(postResponse.id) // #3. fetch author
.then((authorResponse) =>
authorResponse
.json() // #4 get & return author json
.then((authorResponse) =>
getComment(postResponse.id) // #5 fetch comment
.then((commentResponse) => commentResponse.json()) // #6 get & return comment json
.then((commentResponse) => {
// #7 time to combine all results
return {
postResponse,
authorResponse,
commentResponse,
}; // #8 combine & return all reponses
})
)
)
.then((results) => {
// #9 read all responses
console.log(results.postResponse);
console.log(results.authorResponse);
console.log(results.commentResponse);
})
)
.catch((error) => console.log(error)); // # 10 error handling
上面代码是否有种似曾相识的感觉,原本是为了解决回调地狱,但似乎理想跟现实还是有差距。
于是 ES2021 为 Promise 对象增加新的特征,其中包括:Promise.any()
、Promise.all()
、Promise.allSettled()
、Promise.race()
。
Promise.any()
Promise.any(promises)
能够并行运行 promise
,并解析为 promises
列表中第一个成功解析的 promise
的值。需要注意的是 Promise.any()
方法依然是实验性的,尚未被所有的浏览器完全支持。
下面来看看 Promise.any()
是如何工作的。
1.工作原理
Promise.any()
可用于以并行和竞争方式执行独立的异步操作,以获取任何第一个完成的 promise
的值。
该函数接受一个 promise
数组(通常为一个可迭代对象)作为参数,如下:
const anyPromise = Promise.any(promises);
当输入 promises
中的第一个 promise
被执行完成时,anyPromise
会立即解析为该 promise
的值。
可以使用 then
方法提取第一个 promise
的值:
anyPromise.then((firstValue) => {
firstValue; // 第一个 promise 完成后返回的值
});
也可以使用 async/await
语法:
const firstValue = await anyPromise;
console.log(firstValue); // 第一个 promise 完成后返回的值
Promise.any()
返回的 promise
与任何第一个执行的 promise
一起执行。即使某些 promise
被 rejected
,这些 rejections
也将会被忽略。
网友评论