【问题标题】:Mixing a queue of callback functions and jQuery deferreds混合回调函数队列和 jQuery 延迟
【发布时间】:2013-04-01 19:30:31
【问题描述】:

我正在尝试创建一个要调用的函数队列以返回自动完成结果。其中一些是我通过 $.getJSON 调用自己构建的函数,还有一些是由外部开发人员使用what's specified for jQuery UI autocomplete 提供给我的。

例如,这里提供了一个假的。我不知道它是否真正异步或何时可能调用回调:

var providedFunction = function(search, response) {
    setTimeout(function() {
        var arr = ['One', 'Two', 'Demo Custom'];
        response($.grep(arr, function (s) { return s.indexOf(search) === 0; }));
    },5000);
};

然后我想将它与其他一些 $.getJSON 调用结合起来,直到整个列表完成后才继续:

var searchTerm = "Demo";
var allResults = [];
var functionQueue = [];

functionQueue.push(
    $.getJSON( 'http://ws.geonames.org/searchJSON?featureClass=P&style=short&maxRows=50&name_startsWith=' + searchTerm)
    .success( function(data) {
        $.each(data.geonames, function(i,d) { 
            allResults.push(d.name); });
    })
);

functionQueue.push(
    providedFunction(searchTerm, function(data) {
        allResults.push.apply(allResults, data);
    })
);

// wait for all asyc functions to have added their results,
$.when.apply($, functionQueue).done(function() {
    console.log(allResults.length, allResults);
});                

问题在于 $.when 不等待提供的函数完成。它会在所有 $.getJSON 调用完成后立即返回。很明显,我没有正确连接提供的功能,但我不知道该怎么做。

【问题讨论】:

  • providedFunction 不是延迟对象,因此$.when 假定它会立即解决。
  • @KevinB 谢谢,但我不知道如何将其转换为延迟,因为我无法控制它的定义(它已传递给我)

标签: javascript jquery jquery-ui jquery-ui-autocomplete jquery-deferred


【解决方案1】:

如果你决定使用 $.when,你会想要创建一个延迟数组,这样你就可以像这样调用提供的函数:

functionQueue.push( (function(){
        var df = new $.Deferred();
        providedFunction(searchTerm, function(data) {
            allResults.push.apply(allResults, data);
            df.resolve();
        })
        return df;
    })()
);

当然,如果您真的很喜欢,您可以使用这个方便的实用程序将基于回调的 API 转换为基于承诺/延迟的 API:

function castAPItoDeferred(origFunction){
    return function(){
        var df = new $.Deferred(),
            args = Array.prototype.slice.call(arguments, 0);
        // assume that the API assumes the last arg is the callback
        args.push(function(result){
            df.resolve(result);
        });
        try {
            origFunction.apply(null, args);
        } catch(e) {
           df.reject(e);
        }
        return df;
    }
}

这会让你做这样的好事:

providedFunctionAsDeferred = castAPItoDeferred(providedFunction);

functionQueue.push(
    providedFunctionAsDeferred(searchTerm)
    .success( function(data) {
        allResults.push.apply(allResults, data);
    })
);

最后一个警告 - 如果您确实走第二条路线,请记住如果在对象上调用 API 函数(例如 myApi.doSomeAsyncThing),请连接/绑定您的 API 函数

最后,使用 $.when 的替代方法是手动跟踪事物,可能使用计数器。例如,:

var counter = 2; // set your number of ops here

var checkIfFinished = function(){
    if(--counter === 0) {
        triggerAllEventsCompleteFunc(); // replace this with your desired action
    }
}

// call checkIfFinished in all your callbacks

【讨论】:

  • 关于“如果您决定使用 $.when”:是否有更好的方法来调用任意长的 .getJSON 调用 + 这些其他自定义函数的混合,并且在所有函数完成之前不继续?
  • 编辑了我的答案以补充这一点,这实际上取决于您的具体情况以及您提前了解多少/您的代码需要多么灵活。
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 2021-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多