递归中的异步方法如何才能正确返回结果?

时间:2019-07-16 23:50:09

标签: javascript asynchronous

我问了有关如何循环运行异步方法的问题。我现在正在以类似递归的方式进行操作。

How can asynchronous method in loop executed in sequence?

但是,如果第二次成功获取数据库数据,现在我无法将数据传递给最终回调(代码的最后一行)。

  1. 我注意到问题可能是:第二个CallGetDB resolve()我想要的数据,但第一个CallGetDB没有得到那个。然后,首先CallGetDB完成,解决所有问题。但是我不知道如何解决。
function CallGetDB(UID) {
      return new Promise(function(resolve, reject){
        GetDynamodb(UID)
        .then((data)=> {
                  console.log("check before if"+JSON.stringify(data));
                  dbResponse = data;
                  resolve(dbResponse);
                }
            )
        .catch((data)=> {
                if(index++ < 2)
                {
                  console.log("This is "+(index+1)+" try to get data from db with UID.");
                  setTimeout(function(){CallGetDB(UID);},100);
                }
                else
                {
                  console.log("Database multi fetch failed");
                  resolve("Database multi fetch failed");
                }
        });
  });
SendSQS(UID,event).then((data)=>{
    return CallGetDB(data);
 }).then((data)=>{
   console.log("I am at most out:" +JSON.stringify(data));
   response.body=JSON.stringify(data);
   callback(null,response);
 });

2 个答案:

答案 0 :(得分:1)

GetDynamodb(UID)包装在new Promise中是一种反模式,因为它会返回一个承诺。

以下操作会添加一个retries参数,默认值为CallGetDB(),并且当重试在限制范围内时,会在catch()中返回一个新的诺言...。或者抛出新的错误以获取陷入了以下catch()

let sleep = ms => new Promise(r => setTimeout(r, ms));

function CallGetDB(UID, retries = 0) {

  return GetDynamodb(UID)
    .catch((data) => {
      if (retries++ < 2) {
        console.log("This is " + (retries + 1) + " try to get data from db with UID.");
        // return another promise
        return sleep(100).then(() => CallGetDB(UID, retries));

      } else {
        console.log("Database multi fetch failed");
        // throw error to next catch()
        throw new Error("Database multi fetch failed");
      }
    });
}


SendSQS(UID, event).then((data) => {
  return CallGetDB(data);
}).then((data) => {
  console.log("Data Success:" + JSON.stringify(data));
  response.body = JSON.stringify(data);
  callback(null, data);
}).catch(err => /* do something when it all fails*/ );

答案 1 :(得分:1)

发生错误并且index小于2时,您的承诺无法兑现。

if(index++ < 2){
  console.log("This is "+(index+1)+" try to get data from db with UID.");
  setTimeout(function(){CallGetDB(UID);},100);
}

到那时,您的承诺将永远不会实现或拒绝,因为原始的承诺永远不会得到实现,并且无法resolve JSON数据也不会到达您的else分支。这变成了一个未解决的承诺(一个承诺无限期地拖延)。不过,如果GetDynamodb第一次尝试完成,它将起作用。

您可以通过履行if分支内的承诺来解决此问题:

setTimeout(function(){resolve(CallGetDB(UID));},100);

话虽这么说,您可能不应该包装这样的承诺。这与您的方法有点相似:

let delay = ms => new Promise(r => setTimeout(r, ms));

function CallGetDB(UID) {
    return GetDynamodb(UID).then(data => {
        console.log("check before if"+JSON.stringify(data));
        return data;
    }).catch(err => {
        if(index++ < 2){
            console.log("This is "+(index+1)+" try to get data from db with UID.");
            return delay(100).then(() => CallGetDB(UID));
        } else {
            console.log("Database multi fetch failed");
            return "Database multi fetch failed";
        }
    });
});

您还可以使用闭包来确定重试范围,因此您的index变量具有适当的作用域:

let delay = r => new Promise(r => setTimeout(r, ms));

function CallGetDB(retries) {
    let index = retries;
    return function inner(UID){
        return getDynamodb(UID).then((data)=> {
            console.log("check before if"+JSON.stringify(data));
            return data;
        }).catch(err => {
            if(index--){
                console.log("This is "+(retries-index)+" try to get data from db with UID.");
                return delay(100).then(() => inner(UID));
            } else {
                console.log("Database multi fetch failed");
                return "Database multi fetch failed";
            }
        });
    };
}

您现在可以像这样使用:CallGetDB(2)(data)