【问题标题】:Promise.all strange resolution issuePromise.all 奇怪的解决问题
【发布时间】:2021-07-24 02:25:07
【问题描述】:

当我调用时考虑这两个函数 getStatusAll(数据)-

data=[[],['1'],['2'],['3']];

async function getStatusAll(data) {
    console.log("In getStatusAll");
  try{
    let statusPromiseArray =  data.map(async(value) => { 
      result= await this.fetchStatusDBs(value);
      return result;
    });
    statusResolvedArray= await Promise.all(statusPromiseArray)
    return statusResolvedArray;
  }catch(err){
    throw(err);
  }
}

async function fetchStatusDBs(data) {
    console.log("In fetchStatusDBs");
  try{
      //fetch status in dvf_req_id for an dvf_req_id
      if(data.length==0){
        console.log("1");
        dvfStatus = await Promise.resolve("Disabled");
        console.log("2");
        trainingStatus = await Promise.resolve("Disabled");
        console.log("3");
        inferenceStatus = await Promise.resolve("Disabled");
      }
      else {
        console.log("4");
        dvfStatus = await Promise.resolve("Enabled");
        console.log("5");
        trainingStatus = await Promise.resolve("Enabled");
        console.log("6");
        inferenceStatus = await Promise.resolve("Enabled");
      }
      return [dvfStatus,trainingStatus,inferenceStatus];
  }catch(err){
    throw(err);
  }
}

我正在尝试解决 Promise.all 中的多个 Promise 但结果出乎意料。 实际输出-

在 getStatusAll 在 fetchStatusDBs 1 在 fetchStatusDBs 4 在 fetchStatusDBs 4 在 fetchStatusDBs 4 2 5 5 5 3 6 6 6 [["启用","启用","禁用"],["启用","启用","启用"],["启用","启用","启用"],["启用","启用","启用"]]

预期输出-

在getStatusAll中
内部地图
在 fetchStatusDBs
1
2
3
内部地图
在 fetchStatusDBs
4
5
6
内部地图
在 fetchStatusDBs
4
5
6
内部地图
在 fetchStatusDBs
4
5
6
[["禁用","禁用","禁用"],["启用","启用","启用"],["启用","启用","启用"],["启用","启用","启用"]]



但是像这样更改 fetchStatusDB 会以正确的格式返回输出。

async function fetchStatusDBs(data) {
    console.log("In fetchStatusDBs");
  try{
      if(data.length==0){
        dvfStatus = "Disabled";
        trainingStatus = "Disabled";
        inferenceStatus = "Disabled";
      }
      else {
        dvfStatus = "Enabled";
        trainingStatus = "Enabled";
        inferenceStatus = "Enabled";
      }
      return [dvfStatus,trainingStatus,inferenceStatus];
  }catch(err){
    throw(err);
  }
}

有人可以帮帮我吗?

【问题讨论】:

  • 你没有声明 dvfStatus 等等,所以它们要么在单个外部范围内“共享”(如果你在那里声明它们),或者隐式全局变量(如果你没有声明他们在任何地方 - 顺便说一句,这是非常糟糕的做法)。因此,当每个 Promise 都“同时”运行时(实际上并非如此,但最好将其视为同时运行),这些变量的设置和读取以不一定容易预测的方式相互重叠。

标签: javascript node.js promise es6-promise


【解决方案1】:

您的主要问题是fetchStatusDBs 中的状态变量未声明,因此implicitly global。由于您的代码正在进行多个并发调用,这些调用在 await 暂停点交错,它们相互影响 - 一个经典的竞争条件。要解决此问题,只需使用 letvar 声明变量即可。

const data=[[],['1'],['2'],['3']];

async function getStatusAll(data) {
    console.log("In getStatusAll");
    let statusPromiseArray = data.map(this.fetchStatusDBs, this);
    return Promise.all(statusPromiseArray);
}

async function fetchStatusDBs(data) {
    console.log("In fetchStatusDBs");
    let dvfStatus, trainingStatus, inferenceStatus;
//  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    //fetch status in dvf_req_id for an dvf_req_id
    if (data.length==0) {
        console.log("1");
        dvfStatus = await Promise.resolve("Disabled");
        console.log("2");
        trainingStatus = await Promise.resolve("Disabled");
        console.log("3");
        inferenceStatus = await Promise.resolve("Disabled");
    } else {
        console.log("4");
        dvfStatus = await Promise.resolve("Enabled");
        console.log("5");
        trainingStatus = await Promise.resolve("Enabled");
        console.log("6");
        inferenceStatus = await Promise.resolve("Enabled");
    }
    return [dvfStatus, trainingStatus, inferenceStatus];
}

这将产生所需的结果(返回值)。要同时从日志中获得预期的输出,您不能将 map 与异步函数一起使用,然后使用 Promise.all 等待所有承诺,但您需要按顺序进行调用:

async function getStatusAll(data) {
    console.log("In getStatusAll");
    const statusArray = [];
    for (const value of data) {
//  ^^^^^^^^^^^^^^^^^^^^^^^^^
        statusArray.push(await this.fetchStatusDBs(value));
//                       ^^^^^
    }
    return statusArray ;
}

【讨论】:

    【解决方案2】:

    你对 async-await 有几个误解

    async function getStatusAll(data) {
        console.log("In getStatusAll");
      try{
        let statusPromiseArray =  data.map(async(value) => { // map is sync
          result= await this.fetchStatusDBs(value); // global result
          return result; // return-await anti-pattern
        });
        statusResolvedArray= await Promise.all(statusPromiseArray) // global
        return statusResolvedArray; // return-await anti-pattern
      }catch(err){  // catch-throw anti-pattern
        throw(err);
      }
    }

    所有这些都可以写成-

    function getStatusAll(data) {
      return Promise.all(data.map(v => this.fetchStatusDBs(v)))
    }
    

    任何错误都会自动冒泡。无需catch 和重新throw。这将在 parallel 中完成所有提取。如果您愿意,您可以在 serial 中执行请求。这表明在async 中正确使用await -

    async function getStatusAll(data) {
      const result = []
      for (const value of data)
        result.push(await this.fetchStatusDBs(value))
      return result
    }
    

    【讨论】:

    • 知道了,但如果我在下面的代码中使用 await 的结果。那我应该写try and catch吧?
    • ``` 异步函数 getModelsSummary(orgId){ var query="SELECT objective,uid,last_updated_time FROM model_enabled_status where org_id = ? and is_enabled='1'"; console.log("服务中的 getSummaryDetails");尝试{ queryOutputList = await dObject.query(query,[orgId]); reqIDsList = 等待 serviceHelper.getReqIDs(queryOutputList[0]); statusList = 等待 serviceHelper.getStatusAll(reqIDsList); console.log("\n 响应正文:" + JSON.stringify(statusList));返回状态列表; }catch(err){ throw(err); } } ```
    • @UjjwalMadan 不。如果您的catch 块除了重新抛出错误之外还做了其他事情,您应该只写try { … }。 (注意这与 async/await 无关,同步代码也一样)。
    • 没错。如果你看到自己在写... catch(err) { throw error },只需删除整个try/catch 块。 return await someFunc() 也是如此,在 async 函数中它与 return someFunc() 相同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-13
    相关资源
    最近更新 更多