【问题标题】:How to log return value after async/await?异步/等待后如何记录返回值?
【发布时间】:2021-12-13 15:29:45
【问题描述】:

我在下面粘贴了 PoC 代码,其中我删除了很多行,但它显示了我面临的问题/问题。

createPost()ret 变量中返回一个“帖子编号”。除了记录之外,我不需要“帖子编号”。

对于当前的实现,我必须在while 循环之外定义ret,并且由于在NodeJS 事件循环中顺序代码在异步代码之前运行,我希望日志记录将在createPost() 之前执行,这不是我想要的。

问题

createPost()被执行时,是否可以只记录ret

module.exports = async (p) => {
  let ret = 0;

  try {

    while (true) {

      switch (x) {
        case 1:
          isOk = await getStatusCode({ ... });
          break
        case 2:
          isOk = await getString({ ... });
          break
        default:
          throw "";
      };

    ret = await createPost(p);
    appLogger.info(`Created post: ${ret}`);   // I don't need 'ret' for anything else than logging it

  } catch (error) {
    appLogger.error(error);
  }
}

createPost.js

const axios = require('axios');

module.exports = async (c) => {
  try {
    const r = await axios({ ... });
    return r.data.key;
  } catch (error) {
    throw new Error(JSON.stringify(error.response.data, null, 2));
  };

};

【问题讨论】:

    标签: javascript node.js ecmascript-6 async-await


    【解决方案1】:

    ...由于顺序代码在 NodeJS 事件循环中的异步代码之前运行,我希望日志记录将在 createPost() 之前执行,这不是我想要的。

    async 函数中在第一个 await 之后的所有代码都是异步的,而不是同步的。在您的代码中,appLogger.info 调用将在 createPost 完成其工作(异步)之前发生。

    所以没有必要在循环之外声明ret(即使上面不是真的,那也没有什么帮助),你可以内联,见*** cmets:

    module.exports = async (p) => {
      // *** No `ret` here
    
      try {
    
        while (true) {
    
          switch (x) {
            case 1:
              isOk = await getStatusCode({ ... });
              break
            case 2:
              isOk = await getString({ ... });
              break
            default:
              throw "";
          };
    
        const ret = await createPost(p); // *** Declare it here
        appLogger.info(`Created post: ${ret}`);
    
      } catch (error) {
        appLogger.error(error);
      }
    }
    

    代码在await 处异步等待,并且仅在createPost 完成后继续。

    这是一个简化的例子:

    const randomDelay = () => new Promise(resolve => {
        setTimeout(resolve, Math.floor(Math.random() * Math.floor(Math.random() * 300) + 500));
    });
    
    async function doSomethingElse() {
        await randomDelay();
    }
    
    async function createPost(i) {
        await randomDelay();
        return i * 2;
    }
    
    async function example(max) {
        console.log("Starting (this log is synchronous)");
        for (let i = 0; i < max; ++i) {
            await doSomethingElse();
            const ret = await createPost(i);
            console.log(`i = ${i}, ret = ${ret}`);
        }
        console.log("All done");
    }
    
    console.log("Calling example");
    example(5)
    .then(() => {
        console.log("example promise fulfilled");
    })
    .catch(error => {
        console.error("example promise rejected", error);
    });
    console.log("Done calling example, it's running asynchronously");

    技术上,您根本不需要ret,这也可以:

    appLogger.info(`Created post: ${await createPost(p)}`);
    

    但如果是我,我会保留它,如上面第一个代码块所示。更容易调试。

    【讨论】:

    • 当你写“是异步的,不是同步的”时,我不明白“appLogger.info 调用不会发生,直到 createPost 完成它的工作(异步)。”还是您的意思是在第一个await 之后,其余的将在异步队列中按顺序执行?如果这是正确的,那么我原则上可以删除所有await,除了每个async 函数中的第一个on?
    • @SandraSchlichting - 两者都是,真的,但是你关于删除后续awaits 的事情是不正确的。你需要await 来让函数逻辑等到promise 完成。如果您执行a = await x(),函数代码将等待x 返回的promise 结算,并且(如果它已实现)它将实现值分配给a 并继续。但是如果你只是做a = x(),promise 对象本身就会被分配给a,并且代码不会等待promise 解决。 (无论函数中是否有以前的await ,都是如此。)
    • FWIW,我在最近的一本书 JavaScript: The New Toys 的第 8 章中详细介绍了 promises 和 async 函数的第 9 章。如果您有兴趣,我的个人资料中有链接。
    • 这正是我一直在寻找的那种书!
    • @SandraSchlichting - 基本上。本身并没有真正的“异步队列”,它只是一个任务队列(嗯,有两个级别,任务和微任务),其他东西也排队。但是async 函数的目的是让您使用通常的forif 等而不是回调来编写逻辑流程,await 可以说“在继续之前在这里等待一个承诺。 "快乐编码! :-)
    猜你喜欢
    • 2020-03-13
    • 1970-01-01
    • 2017-09-24
    • 2013-03-22
    • 2013-02-14
    • 2020-08-19
    • 2013-07-24
    • 2019-03-20
    相关资源
    最近更新 更多