• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

JavaScript回调、承诺和异步函数:二

JavaScript回调、承诺和异步函数:二  第1张

介绍

在本教程的第一部分,我们学习了异步编程和使用回调的原理。回顾一下,异步编程允许我们通过稍后执行阻塞任务来编写非阻塞代码。回调函数提供了一种同步代码执行的方法。 

然而,重复嵌套回调并不是一个好的模式。这里有拯救的承诺。Promise 已经在javascript库中使用了一段时间,但现在您可以在代码中本地使用它们。异步函数通过允许我们一个接一个地编写任务而不用担心它们的执行时间来改进 Promise。

内容

  • 承诺

  • 异步函数

  • 审查

  • 资源

承诺

让我们从概念上看一下 Promise 是什么。想象一下您在网上购物并购买了一双鞋的场景。结帐时,您会收到一份购买摘要的电子邮件。 

这个订单确认就像一个承诺。承诺是您保证您稍后会从公司获得一些回报。当您的订单待处理时,您的生活当然不会停止。您继续执行其他任务,例如上网。如果您的订单已完成,您将收到一封包含运输信息的电子邮件。您的订单有可能被拒绝。您订购的商品可能缺货,或者您的付款方式可能存在问题。在这种情况下,您会收到一封电子邮件,告诉您该错误。

在代码中,promise 是一个对象,它确保我们将获得请求的未来值,无论它成功还是失败。这是创建和使用 Promise 的一般形式:

function task1() {
    return new Promise(function(resolve, reject) {
        resolve(data);
        reject(error);
    });
}

task1()
.then(function(result){
    console.log(result);
})
.catch(function(error){
    console.log(error);
});

要创建一个 Promise,您需要实例化一个 Promise 对象并在 Promise 的回调函数中编写异步代码。您希望从 promise 返回的数据作为参数传递给resolve函数,而您的错误消息将传递给reject函数。then我们使用该方法将 Promise 链接在一起。这让我们可以按顺序执行任务。 

如果我们需要将一个任务的结果传递给下一个任务,我们在then方法中返回它。当我们对转换值感兴趣或需要以特定顺序执行代码时,我们可能希望将 Promise 链接在一起。在链的末端,我们捕获了我们的错误。如果我们的任何任务发生错误,则跳过其余任务,并将错误发送到我们的 catch 块。

在本教程的第一部分中,我们使用回调来打开文件并检索帖子及其评论。这是使用 Promise 的完整代码的样子:

index.js

const fs = require('fs');
const path = require('path');
const postsUrl = path.join(__dirname, 'db/posts.json');
const commentsUrl = path.join(__dirname, 'db/comments.json');

//return the data from our file
function loadCollection(url) {
    return new Promise(function(resolve, reject) {
        fs.readFile(url, 'utf8', function(error, data) {
            if (error) {
                reject('error');
            } else {
                resolve(JSON.parse(data));
            }
        });
    });
}

//return an object by id
function getRecord(collection, id) {
    return new Promise(function(resolve, reject) {
        const data = collection.find(function(element){
            return element.id == id;
        });

        resolve(data);
    });
}

//return an array of comments for a post
function getCommentsByPost(comments, postId) {
    return comments.filter(function(comment){
        return comment.postId == postId;
    });
}

//initialization code
loadCollection(postsUrl)
.then(function(posts){
    return getRecord(posts, "001");
})
.then(function(post){
    console.log(post);
    return loadCollection(commentsUrl);
})
.then(function(comments){
    const postComments = getCommentsByPost(comments, "001");
    console.log(postComments);
})
.catch(function(error){
    console.log(error);
});

这里的区别是我们打开文件的方法现在被包装在一个 promise 对象中。并且不是用回调嵌套我们的任务,而是用then. 

如您所见,我们并没有消除对回调的需求。我们只是以不同的方式使用它们。之前,我们嵌套了回调,以便我们可以在下一个任务中继续执行我们的代码。 

这让我想起了当我打电话给客户服务部解决问题时,我没有被代理解决我的问题,而是被转移给了其他人。其他人可能会或可能不会解决呼叫,但就第一个代理而言,这是其他人的责任。 

有了承诺,我们将在进行下一个任务之前得到一些回报。如果我们需要将这些东西带到我们代码的下一个延续,我们可以使用一个 then语句。

任务

使用 Promise,编写一个程序,该程序将打开一个用户文件,获取用户信息,然后打开一个帖子文件并打印所有用户的帖子。

异步函数

Promise 是对我们程序设计的改进,但我们可以做得更好。如果我们可以像这样同步执行我们的任务将非常方便:

task1();
task2();
task3();

好吧,我们可以使用 async/await 模式。为此,我们首先将任务包装在异步函数中。此函数返回一个承诺。然后我们通过将我们的任务包装在一个try/catch 语句中来实现错误处理。 

如果实现了承诺,它将完成我们try块内的任何任务。如果被拒绝,该catch块将被执行。在任何任务之前添加await 关键字会暂停我们的程序,直到任务完成。 

这是使用异步函数的一般形式:

async function initTasks () {
    try {
        const a = await task1();
        const b = await task2();
        const c = await task3();
        //do something with a, b, and c
    } catch (error) {
        //do something with the error object
    }
}

initTasks();

使用这种模式,我们可以重写我们在文件示例中执行代码的方式。

async function getPost(){
    try {
        const posts = await loadCollection(postsUrl);
        const post = await getRecord(posts, "001");
        const comments = await loadCollection(commentsUrl);
        const postComments = await getCommentsByPost(comments, post.id);
        
        console.log(post);
        console.log(postComments);
    } catch (error) {
        console.log(error);
    }
}

getPost();

我喜欢用try/catch语句来构建我们的异步代码,因为它清楚地将错误处理代码与常规代码分开。如果我们try块中的任何代码导致错误,它将由catch块处理。另外,我们可以添加一个finally块来执行代码,无论我们的任务是成功还是失败。 

使用这种模式的一个例子是当我们需要执行清理代码时。此代码不一定必须包含在finally块中。它可以写在catch语句之后,它会执行。Promise 没有内置这种语法。我们必须then在我们的语句之后链接另一个语句catch才能达到相同的效果。

任务

使用 async/await,编写一个程序,该程序将打开一个用户文件,获取用户信息,然后打开一个帖子文件并打印用户信息和他们所有的帖子。

审查

回调本质上并不是邪恶的。将函数传递给其他函数是 JavaScript 中一种有用的模式。当我们使用回调来控制应用程序逻辑的流程时,回调成为一个问题。由于 javaScript 是异步的,我们必须注意如何编写代码,因为任务不一定按照它们编写的顺序完成。这不是一件坏事,因为我们不希望任何任务阻碍程序的继续。 

Promise 是编写异步代码的更好模式。它们不仅修复了嵌套回调的混乱,而且还在任务中控制了任务的结果。将控制权传递给另一个任务,无论该任务是我们自己的代码还是第三方api,都会降低我们的代码的可靠性。最后,异步函数允许我们同步编写代码,这更直观、更容易理解。


文章目录
  • 介绍
  • 内容
  • 承诺
    • index.js
    • 任务
  • 异步函数
    • 任务
  • 审查