Reputation: 2350
I have a chain of deferreds in a javascript submit handler that make series of AJAX calls to an API until the desired result is returned. It worked well, but I made a tweak and now I am unable to figure out where I went wrong, because the new code seems to have a broken chain of promises.
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
});
The console output of which is
waiting for job to finish
Object {job: "{"error": "Job not found"}"}
Object {job: Object}
resolving wait for job status
Which makes sense: the first line is just before waitForJobStatus
getting called, then waitForJobStatus
tries once and fails to find a job, then tries again after 1 second and finds a job, so it logs the data
, and finally just before I resolve, I add a console message to prove that we made it into the conditional.
But then the console.log('got job status, updating and resolving');
never fires - the waitForJobStatus
doesn't get resolved, I guess, so the then
in createLinkAPIJob
never fires
Upvotes: 0
Views: 193
Reputation: 665536
You misidentified the problem area. In that if
branch, the deferred is resolved fine. The problem is the else
branch:
… else {
return $.promiseDelay(1000).then(function() {
return waitForJobStatus(jobID, timeStarted);
});
}
Here, def
is never resolves (and is not rejcted either)! This stems from your usage of the deferred antipattern - if you had not used a deferred, return
ing from a then
callback would indeed work. You are supposed to do such chaining only. If you are calling functions that already return promises, never create a deferred (you did unusually well by factoring out $.promiseDelay
already)!
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 …;
});
}
Upvotes: 1