【问题标题】:Combine async and sync function results properly正确组合异步和同步函数结果
【发布时间】:2021-08-16 23:56:29
【问题描述】:

我尝试组合两个函数值(来自a()b()),但代码没有像预期的那样等待函数test 中的等待语句。相反,结果值直接打印错误的结果。

function resData(status, message) {
  return { ok: status, message: message };
}

function a() { 
  return resData(true, 'A'); 
}

async function b() {
  // simulate some long async task (e.g. db call) and then return the boolean result
  function sleep(ms) {
    return new Promise((resolve) => {
      setTimeout(resolve, ms);
  }); }
  await sleep(2500);
  return resData(true, 'B');
}

async function isValid() {
  const promises = [a, b].map(async (fnc) => { return await fnc().ok; });
  const results = await Promise.all(promises);
  // combine the results to one boolean value
  return results.every(Boolean);
}

async function test() {
  // not waiting here
  const res = await isValid();
  // prints directly - wrong result false
  console.log('result', res);
}

test();

在错误的结果输出后等待 2.5 秒。我认为这与 resData 的函数调用有关,但我自己无法弄清楚,我的 async / await 误解在哪里。提前致谢。

【问题讨论】:

  • await fnc().ok -> (await fnc()).ok 否则你只是在等待undefined,因为fnc() 返回一个承诺,.ok 在该承诺上返回undefined

标签: javascript node.js async-await


【解决方案1】:

您不是在等待函数被解析,而是在等待函数返回值。

async function isValid() {
  const promises = [a, b].map(async (fnc) => {

    //return await fnc().ok;
    // You have to await first function then call `.ok` value
     return (await fnc()).ok;
  });
  const results = await Promise.all(promises);
  // combine the results to one boolean value
  return results.every(Boolean);
}

为了简化问题,请检查以下代码。

async function test() {
  return { ok: true };
}
async function main() {
  // trying to await on undefined.. test().ok == undefined
  console.log(await test().ok); // undefined
  // first await function.. then return ok
  console.log((await test()).ok); // true
}
main();

【讨论】:

    【解决方案2】:

    我会说你的代码有 2 1 个问题

    1. a 没有返回一个承诺,所以你不能把它当作一个承诺 - 忽略事实证明你可以,谁知道呢!
    2. 你不能等待一个布尔值,所以await fnc().ok 没有意义。

    我建议你

    1. a 返回一个承诺,即使它只是一个已解决的承诺
    2. 只执行map 中的方法
    3. every 调用中读取ok 的值,以确定是否所有承诺都在此值设置为true 时得到解决

    通过这些更改,我怀疑您在写入控制台之前需要等待 2.5 秒。

    function resData(status, message) {
      return { ok: status, message: message };
    }
    
    function a() { 
      return resData(true, 'A'); 
    }
    
    async function b() {
      // simulate some long async task (e.g. db call) and then return the boolean result
      function sleep(ms) {
        return new Promise((resolve) => {
          setTimeout(resolve, ms);
      }); }
      await sleep(2500);
      return resData(true, 'B');
    }
    
    async function isValid() {
      const promises = [a, b].map(fnc => fnc());
      const results = await Promise.all(promises);
      // combine the results to one boolean value
      return results.every(x => x.ok);
    }
    
    async function test() {
      // not waiting here
      const res = await isValid();
      // prints directly - wrong result false
      console.log('result', res);
    }
    
    test();

    【讨论】:

    • 你确实可以在普通(不仅仅是Promise)对象上await
    • 您不仅可以await 处理任何事情,还可以使用诸如Promise.all() 之类的promise 静态方法处理任何事情。正是因为 Promise 可以解决任何问题。
    • @Jamiec 顺便说一句,就我的浏览器显示而言,答案中仍然有“你不能等待布尔值”。
    • @Jamiec 非常感谢您的回答。也感谢评论部分的提示。我也不知道,所有这些反对票是从哪里来的。
    • @Habebit 不用担心。所以有时可能很奇怪,你的问题没有错。
    【解决方案3】:

    异步函数隐式返回一个承诺,该承诺最终将解析为函数执行结束时返回的最终值。

    因此,您只需在 map 回调中调用您的函数即可收集 Promise。结果数组将是resData 对象的数组。因此,您最终检查每个 ok 属性是否符合您的要求。

    function sleep(ms) {
      return new Promise((resolve) => {
        setTimeout(resolve, ms);
      });
    }
    
    function resData(status, message) {
      return {ok: status, message: message};
    }
    
    function a() { 
      return resData(true, 'A'); 
    }
    
    async function b() {
      await sleep(2500);
      return resData(true, 'B');
    }
    
    async function isValid() {
      const promises = [a, b].map((fnc) => fnc());
      const results = await Promise.all(promises);
      return results.every((result) => result.ok);
    }
    
    async function test() {
      const res = await isValid();
      console.log('result', res);
    }
    
    test();

    【讨论】:

    • 我的意思是,我的答案几乎是复制/粘贴,没有轻微的失礼,但没关系。
    • @Jamiec 直到我发布了我的答案后才看到您的答案。代码 99% 是由 OP 编写的,所以实际上我们都是从他那里抄来的,而且答案很相似(尽管我们写的东西不同)。最后,我在这里没有对任何人投反对票,但如果你问我,你在回答中写了很多不准确的东西,在混淆人们之前你应该确定一些事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-10-20
    • 2020-04-11
    • 2021-08-01
    • 2019-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-12-27
    相关资源
    最近更新 更多