如何轮询 API 作为 $.Deferred() 的一部分

How to poll an API as part of a $.Deferred()

下面的非功能性示例应该可以解释我正在尝试做什么,我只是不明白我需要使用什么模式来完成它。我尝试使用谷歌搜索来了解轮询和延迟,但找不到任何我能理解的内容。

我有一个轮询 API 的函数,我想等待该轮询 return 预期结果(等待端点指示某些内容已更改),然后再继续我的操作主功能。我做错了什么?

编辑:我应该补充一点,SEEMS 在下面的代码中出错的地方是,即使 deferred.resolve() 最终被调用,它似乎与 deferred 不一样24=]ed,所以 when 永远不会在 main() 中被激活。我猜它与超时有关,这意味着 deferred 在第一次重复时被破坏。无论如何,这是我的假设。

function pollAPI() {
     var deferred = $.Deferred();

     $.ajax({                                                                  
       url: url,                                       
       contentType: 'application/JSON',                                      
       method: 'GET'                                                         
     }).done(function(data){                                                                                                                              
         if (!desiredResult) {                                                 
             setTimeout(function() {                                         
               pollAPI();                            
             }, 1000);                                                       
         } else {                                                            
           deferred.resolve();
         }                                                                                                                                           
     }).error(deferred.reject());                                            

     return deferred.promise();
 }

function main() {
    $.when(pollAPI()).then(function() {
        // do something now that the API has returned the expected result
    });

您可以使用对 pollAPI() 函数的后续调用的链接来创建一个具有其他链接的承诺。那会像这样工作:

// 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 pollAPI() {
    return $.ajax({
        url: url,
        contentType: 'application/JSON',
        method: 'GET'
    }).then(function(data) {
        // some logic here to test if we have desired result
        if (!desiredResult) {
            // chain the next promise onto it after a delay
            return $.promiseDelay(1000).then(pollAPI);
        } else {
            // return resolved value
            return someValue;
        }
    });
}

function main() {
    pollAPI().then(function(result) {
        // got desired result here
    }, function(err) {
        // ended with an error here
    });
}

这有以下好处:

  1. 没有创建不必要的承诺来尝试包围已经有承诺的 ajax 调用。这避免了 common promise anti-patterns.
  2. 之一
  3. 对 API 的后续调用只是链接到原始承诺。
  4. 当你只有一个承诺时,不需要使用 $.when()。你可以直接在上面使用 .then()
  5. 所有错误都会自动回溯到最初的承诺。
  6. 这使用了 ES6 标准 .then()(实际上它在 jQuery 3.x 中变得更加合法标准 - 虽然它在 jQuery 1.x 中有效并且2.x 有它自己的非标准怪癖)这使得这个逻辑与其他产生承诺的异步函数更兼容。

此外,这里还有一些其他的重试想法: