延期未解决
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 的使用 - 如果您没有使用延迟,return
从 then
回调中确实可以工作。你应该只做这样的链接。如果你正在调用已经 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 …;
});
}
我在 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 的使用 - 如果您没有使用延迟,return
从 then
回调中确实可以工作。你应该只做这样的链接。如果你正在调用已经 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 …;
});
}