0

我想創建一個函數隊列來調用返回自動完成結果。其中一些是我從$ .getJSON調用構建自己的函數,有些是由外部開發人員使用what's specified for jQuery UI autocomplete提供給我的。混合回調函數和jQuery延期隊列

例如,這裏提供了一個假的。我不知道前面,如果是真正的異步或什麼時候會調用回調:

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調用完成,它就會返回。很明顯,我沒有正確地連接提供的功能,但我不知道如何去做。

+0

'providedFunction'不是延遲對象,因此'$ .when'假定它立即被解析。 –

+0

@KevinB謝謝,但我不知道如何將它轉換爲延遲,因爲我不控制它的定義(它傳遞給我) –

回答

2

如果你有你的心臟上使用$。當設置,你需要創建deferreds數組,所以你可以調用提供的函數是這樣的:

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 funcs中,如果他們是在調用的對象(如myApi.doSomeAsyncThing

最後,使用$。當一個替代方案是手動記錄事情,可能使用計數器。例如:

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 
+0

關於「如果你有你的心設置使用$ .when」:有沒有更好的方法來調用任意長的.getJSON調用+這些其他自定義函數的混合,而不是繼續,直到所有完成? –

+0

編輯我的答案補充說,真的這取決於你的具體情況,以及你事先知道多少/你的代碼需要多麼靈活。 –

+0

謝謝,有道理 –