在本教程中,您将学习有关在 JavaScript 中使用 Promise 和 async/await 所需了解的所有内容。
那么让我们开始吧。
ES6 引入了 Promise 作为原生实现。在 ES6 之前,我们使用回调来处理异步操作。
让我们了解什么是回调以及 Promise 解决了哪些与回调相关的问题。
假设我们有一个帖子列表及其各自的评论,如下所示:
const posts = [
{ post_id: 1, post_title: 'First Post' },
{ post_id: 2, post_title: 'Second Post' },
{ post_id: 3, post_title: 'Third Post' },
];
const comments = [
{ post_id: 2, comment: 'Great!'},
{ post_id: 2, comment: 'Nice Post!'},
{ post_id: 3, comment: 'Awesome Post!'},
];
现在,我们将编写一个函数,通过传递帖子 ID 来获取帖子。如果找到该帖子,我们将检索与该帖子相关的评论。
const getPost = (id, callback) => {
const post = posts.find( post => post.post_id === id);
if(post) {
callback(null, post);
} else {
callback("No such post found", undefined);
}
};
const getComments = (post_id, callback) => {
const result = comments.filter( comment => comment.post_id === post_id);
if(result) {
callback(null, result);
} else {
callback("No comments found", undefined);
}
}
在上面的getPost
函数中getComments
,如果出现错误,我们会将其作为第一个参数传递。但是如果我们得到结果,我们将调用回调函数并将结果作为第二个参数传递给它。
如果您熟悉 Node.js,那么您就会知道这是每个 Node.js 回调函数中使用的非常常见的模式。
现在让我们使用这些函数:
getPost(2, (error, post) => {
if(error) {
return console.log(error);
}
console.log('Post:', post);
getComments(post.post_id, (error, comments) => {
if(error) {
return console.log(error);
}
console.log('Comments:', comments);
});
});
执行上述代码后,您将看到以下输出:
调用 getPost 和 getComments 函数的结果
正如您所看到的,我们将getComments
函数嵌套在getPost
回调中。
现在想象一下,如果我们也想找到这些评论的点赞。这也会嵌套在getComments
回调中,从而创建更多嵌套。这最终会让代码变得难以理解。
这种回调嵌套称为回调地狱。
您可以看到错误处理条件也在代码中重复,这会创建重复的代码 - 这不好。
因此,为了解决这个问题并允许异步操作,引入了 Promise。
Promise 是 JavaScript 最重要的部分之一,但它们可能会令人困惑且难以理解。许多新开发人员以及经验丰富的开发人员都很难完全掌握它们。
那么什么是承诺呢?Promise 代表一个异步操作,其结果将在将来出现。
在 ES6 之前,没有办法等待某些东西来执行某些操作。例如,当我们想要进行API调用时,没有办法等到结果返回。
为此,我们曾经使用 JQuery 或 Ajax 等外部库,它们有自己的 Promise 实现。但 Promise 没有 JavaScript 实现。
但后来在 ES6 中添加了 Promise 作为原生实现。现在,使用 ES6 中的 Promise,我们可以自己进行 API 调用,并等待它完成后再执行某些操作。
要创建 Promise,我们需要使用Promise
如下的构造函数:
const promise = new Promise(function(resolve, reject) {
});
构造Promise
函数将函数作为参数,该函数在内部接收resolve
和reject
作为参数。
和参数实际上是我们可以根据异步操作的结果调用的函数resolve
。reject
APromise
可以经历三种状态:
当我们创建一个承诺时,它处于待处理状态。当我们调用该resolve
函数时,它会进入已完成状态,如果我们调用reject
它,它将进入拒绝状态。
为了模拟长时间运行或异步操作,我们将使用该setTimeout
函数。
const promise = new Promise(function(resolve, reject) {
setTimeout(function() {
const sum = 4 + 5;
resolve(sum);
}, 2000);
});
在这里,我们创建了一个承诺,它将在 2000 毫秒(2 秒)超时结束后解析为 和 的总和4
。5
为了获得成功执行 Promise 的结果,我们需要使用.then
如下方式注册一个回调处理程序:
const promise = new Promise(function(resolve, reject) {
setTimeout(function() {
const sum = 4 + 5;
resolve(sum);
}, 2000);
});
promise.then(function(result) {
console.log(result); // 9
});
因此,每当我们调用 时resolve
,promise 都会返回传递给resolve
函数的值,我们可以使用.then
处理程序收集该值。
如果操作不成功,那么我们reject
这样调用该函数:
const promise = new Promise(function(resolve, reject) {
setTimeout(function() {
const sum = 4 + 5 + 'a';
if(isNaN(sum)) {
reject('Error while calculating sum.');