延期未解决

Deferred is not resolving

我在 javascript 提交处理程序中有一个延迟链,它对 API 进行一系列 AJAX 调用,直到返回所需的结果。它运行良好,但我做了一些调整,现在我无法弄清楚我哪里出错了,因为新代码似乎有一个破碎的承诺链。

function createLinkAPIJob(type) {
  //code to create a request
  return $.ajax(request)
}

function getJobStatus(jobID) {
  return $.ajax({
    url: Urls['find_job'](jobID),
    contentType: 'application/JSON',
    method: 'GET'
  })
}

// utility function to create a promise that is resolved after a delay
$.promiseDelay = function(t) {
  return $.Deferred(function(def) {
    setTimeout(def.resolve, t);
   }).promise();
 }

function waitForJobStatus(jobID, timeStarted) {
  return $.Deferred(function(def) {

    getJobStatus(jobID).then(function(data) {
      console.log(data);
      var isFinished = data['job']['finished'];
      var jobStatus = 'incomplete';
      var jobStatus = data['job']['job_status'];
      if (isFinished === true) {
        /***** HERE IS THE PROBLEM AREA *****/
        console.log('resolving wait for job status');
        def.resolve(jobStatus);
        //also tried: return jobStatus;
      } else {
        return $.promiseDelay(1000).then(function() {
          return waitForJobStatus(jobID, timeStarted);
        });
      }
    });

  }).promise();
}

function executeLinkAPIJob(type) {
  return $.Deferred(function(def) {

    createLinkAPIJob(type).then(function(response) {
      var jobID = response['data']['job_id'];
      var timeStarted = new Date().getTime() / 1000;
      console.log('waiting for job to finish');
      waitForJobStatus(jobID, timeStarted).then(function(jobStatus) {
        console.log('got job status, updating and resolving');
        // A bunch of code here that doesn't matter for this issue...
        def.resolve();
      });
    });

  }).promise();
} 

// I know this seems stupid in this example, but jobs is sometimes a longer array
jobs = [executeLinkAPIJob(type=type)]
.when.apply($, jobs).then(function() {
  // do something
});

其控制台输出为

waiting for job to finish
Object {job: "{"error": "Job not found"}"}
Object {job: Object}
resolving wait for job status

这是有道理的:第一行就在 waitForJobStatus 被调用之前,然后 waitForJobStatus 尝试了一次但找不到工作,然后在 1 秒后再次尝试并找到了工作,所以它记录了 data,最后在我解决之前,我添加了一条控制台消息以证明我们已将其纳入条件。

但是 console.log('got job status, updating and resolving'); 永远不会触发 - 我猜 waitForJobStatus 没有得到解决,所以 createLinkAPIJob 中的 then 永远不会触发

您错误地识别了问题区域。在那个 if 分支中,延迟被很好地解决了。问题是 else 分支:

… else {
  return $.promiseDelay(1000).then(function() {
    return waitForJobStatus(jobID, timeStarted);
  });
}

在这里,def 永远不会解决(也不会被拒绝)!这源于您对 deferred antipattern 的使用 - 如果您没有使用延迟,returnthen 回调中确实可以工作。你应该只做这样的链接。如果你正在调用已经 return 承诺的函数,永远不要创建延迟(你已经通过分解 $.promiseDelay 做得非常好)!

function waitForJobStatus(jobID, timeStarted) {
  return getJobStatus(jobID).then(function(data) {
    console.log(data);
    var isFinished = data['job']['finished'];
    var jobStatus = 'incomplete';
    var jobStatus = data['job']['job_status'];
    if (isFinished === true) {
      console.log('resolving wait for job status');
      return jobStatus; // this is correct indeed
    } else {
      return $.promiseDelay(1000).then(function() {
        return waitForJobStatus(jobID, timeStarted);
      });
    }
  });
}

function executeLinkAPIJob(type) {
  return createLinkAPIJob(type).then(function(response) {
    var jobID = response['data']['job_id'];
    var timeStarted = new Date().getTime() / 1000;
    console.log('waiting for job to finish');
    return waitForJobStatus(jobID, timeStarted);
  }).then(function(jobStatus) {
    console.log('got job status, updating and resolving');
    // A bunch of code here that doesn't matter for this issue...
    return …;
  });
}