Javascript:反复调用promises,直到返回所需结果并在之后触发事件?

时间:2017-11-12 17:25:21

标签: javascript node.js ecmascript-6 promise

我目前有这个问题,我在javascript中调用API来返回已提交作业的状态。工作状态可以是“QUEUED”,“RUNNING”或“COMPLETED”。我以promise的形式收到此API调用的结果。我有一个名为pollJob的函数,它进行API调用并返回一个最终解析的promise,让我知道作业是否完成。我的问题是,我必须多次调用pollJob,直到我得到一个解析为'COMPLETED'的作业状态,然后发出某种通知,以便在前端触发某种操作,从而导致结果发生。

这是我到目前为止尝试做的一个例子,但它不起作用,因为Javascript没有延迟功能的概念,每个超时都不会阻止,而是关闭,让代码继续,然后一旦分配的时间过去,就触发包含代码。我正在使用setTimeout并将每个循环乘以延迟以在交错的实例中进行调用,基本上分散每个API调用,因为完成工作可能需要一分钟:

  var res = "";
  var i = 0;
  var delay = 1000;
  while (!api.isJobDone(res) && i < 15) {
    setTimeout(function() {
      api.pollJob()
      .then(function(status) {
        console.log("STATUS IN LOOPUNTILDONE: " + status);  
        (res = status)
        if (api.isJobDone(status)) {
          // let the front end know the job is complete
        }
      });
    }, delay);
    delay *= 3;
    i++;
  }
  return res;

我在以异步方式思考这段代码时遇到了很多麻烦,并且很难思考如何在循环中调用此承诺,直到它给出了我想要的结果,然后将该信息发送给前端让代码的那部分知道继续。有没有更聪明的方法来设计它?任何建议或提示都非常感谢。谢谢!

2 个答案:

答案 0 :(得分:3)

如果您使用的是Node 8,则可以使用async/await,以便以可读的方式编写它。

// a delay function
function wait(delay){
    return new Promise(resolve => setTimeout(resolve, delay))
}

// poll in while loop until conditions are met
async function poll(){
    let res
    let i = 0
    const DELAY = 1000
    while (!api.isJobDone(res) && i < 15){
        res = await api.pollJob()
        console.log("STATUS IN LOOPUNTILDONE: " + res); 
        if (api.isJobDone(res)) {
            console.log("done")
        }
        await wait(DELAY)   
        i++     
    }
}
// make it so
poll()

这是一个带有模拟api的片段,应该在现代浏览器中运行:

&#13;
&#13;
// mock api
var api = {
  pollJob: function() {
    return new Promise((resolve) => {
      setTimeout(() => resolve(Math.random()), 500)
    })
  },
  isJobDone: function(status) {
    return status < 0.3
  }
}

function wait(delay) {
  return new Promise(resolve => setTimeout(resolve, delay))
}

async function poll() {
  let res
  let i = 0
  const DELAY = 1000
  while (!api.isJobDone(res) && i < 15) {
    res = await api.pollJob()
    console.log("STATUS IN LOOPUNTILDONE: " + res);
    if (api.isJobDone(res)) {
      console.log("done")
    }
    await wait(DELAY)
    i++
  }
}
poll()
&#13;
&#13;
&#13;

答案 1 :(得分:1)

这可能更适合递归,而不是使用while循环:

function checkIfJobIsDone() {
    api.pollJob().then(function(status) {
        console.log("STATUS IN LOOPUNTILDONE: " + status); 
        res = status;
        if (api.isJobDone(status)) {
            // let the front end know the job is complete
        } else {
            checkIfJobIsDone();
        }
    });
}

这样,在上一个API返回之前,它不会再进行另一个API调用