2016-09-21 5 views
0

У меня есть цепочка отложенных запросов в обработчике отправки javascript, которые делают серии вызовов AJAX API, пока не будет возвращен желаемый результат. Это сработало хорошо, но я сделал настройку, и теперь я не могу понять, где я ошибся, потому что новый код, похоже, сломанная цепочка обещаний.Отложенное не разрешает

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 не разрешится, я думаю, так что then в createLinkAPIJob никогда не стреляет

ответ

1

Вы распознали проблемную область. В этой ветке if отложенное разрешение прекращается. Проблема заключается в else ветви:

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

Здесь def никогда не решает (и не rejcted либо)! Это связано с использованием вами deferred antipattern - если вы не использовали отложенное, return ing с обратного вызова then действительно сработает. Вы должны делать такую ​​цепочку. Если вы вызываете функции, которые уже возвращают обещания, никогда не создавайте отложенные (вы делали необычно хорошо, разыгрывая $.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 …; 
    }); 
} 
+0

Большое спасибо за ответ и пример кода. Этот ответ только наполовину имел смысл для меня вчера (как и большинство ответов, которые я получил о обещаниях за последние несколько месяцев), что разочаровало меня в том, что я купил JavaScript с обещаниями и прочитал его вчера и сегодня утром, что было давно назрело. Могу ли я снова приехать сюда с непониманием о обещаниях! – fildred13

Смежные вопросы