How can asynchronous method in recursion return re

2019-08-18 23:01发布

I asked question about how to run asynchronous method in loop. And I am now doing it in something like recursion.

How can asynchronous method in loop executed in sequence?

But now I can't get data pass to final callback(last line of my code), if db data is fetched successfully at second time.

  1. I notice the problem may be: second CallGetDB resolve() the data I want but first CallGetDB doesn't get that. Then first CallGetDB finished wihtout resolve anything. But I don't know how to solve it.
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条回答
不美不萌又怎样
2楼-- · 2019-08-18 23:10

Your promise isn't resolving in the event of an error and an index lower than 2. Here:

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

At that point, your promise will never fulfill or reject as the original promise never gets fulfilled and can't resolve the JSON data nor does it hit your else branch.It becomes an unresolved promise (a promise stalled indefinitely). It will work in the event that GetDynamodb fulfills on the first attempt though.

You can fix this by fulfilling the promise inside the if branch:

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

That being said, you probably shouldn't be wrapping promises like this. This is a somewhat similar approach to yours:

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";
        }
    });
});

You can also use a closure for scoping retries, so you have a proper scope for your index variable:

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";
            }
        });
    };
}

Which you can now use like: CallGetDB(2)(data)

查看更多
Lonely孤独者°
3楼-- · 2019-08-18 23:22

Wrapping GetDynamodb(UID) in a new Promise is an anti-pattern since it returns a promise.

Following adds a retries parameter with a default to CallGetDB() and either returns a new promise in the catch() when retries are within limits.... or throws a new error to get caught in following 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*/ );
查看更多
登录 后发表回答