如何返回将使用多个函数的结果解决的promise?

时间:2012-04-15 15:57:33

标签: jquery jquery-deferred

我正在开发一个jQuery插件,它假装根据用户的浏览器语言自动翻译页面上的元素。翻译将存储在.json文件中。

当你调用插件时,你传递一个包名(或它们的数组),然后它将尝试以下列方式加载语言文件:

  • 如果浏览器的语言很简单,例如'en'并且您只指明了一个包,它会尝试加载以下内容:packageName-en.json
  • 如果组成了浏览器的语言,例如“en-US”,则会尝试加载与之前相同的语言,但使用:packageName-en.json AND packageName-en-US.json
  • 如果指示了多个包,它将尝试按照每个包的前两个路径之一。

所以,在插件中我有这个:

$.fn.Translator = function(pkg, options){
    Translator.initialize(pkg, options).done(function(){
        return this.each(Translator.translate);
     });            
};

所以,在我的初始化函数中,我有这个:

loadLanguages : function(){
    $.each(self.options.packages,function(i, pkg){

    });
}

将调用此函数:

getLanguage : function(pkg, language){
    var self = this, url;
    if (self.options.path)
        url = self.options.path + '/';
    url += [pkg, language].join('-');

    return $.ajax ({
        url : url,
        dataType : "json",
        cache : self.options.cache
    });
}

问题在于,由于该函数可能会被多次调用,我不知道如何让initialize返回一个将在调用所有函数后解析的promise。

2 个答案:

答案 0 :(得分:2)

我知道你已经接受了答案,但有一种更简单的方法:使用$.when

function loadLanguages () {
    return $.when.apply( $, $.map( self.options.packages, function( pkg ) {
        return getLanguage(pkg, language);
    }) );
}

答案 1 :(得分:0)

要解决此问题,您可以创建一个虚拟Deferrer(baseDfr)并返回虚拟结果initialize()。这里的想法是在完成所有baseDfr.resolve()次呼叫时致电getLanguage()。我们会跟踪使用计数器完成的getLanguage()次呼叫的数量。当计数器达到0时,我们调用baseDfr.resolve()。 我们知道getLanguage()使用then()done()方法在$.ajax返回的延期者上完成调用。

可以在下面找到解决此问题的代码。此外,可以在此处找到一个工作示例(在某些div上):http://jsfiddle.net/c5NBr/。打开控制台以查看消息的正确顺序。

var packages = [];
var count = 0;
var baseDfr = $.Deferred();
var language = "en";

function resolveFunction () {
    // By using this approach it is possible to pass a 
    // parameter to this resolve function.
    return function(){
        if ( !(--count) ) {
            // Until count is 0, we won't resolve the base
            // deferrer object.
            // As long as this isn't called, the function
            // done() of initialize won't be called either.
            baseDfr.resolve();
        }     
    };
}

function getLanguage (pkg, language){
    var self = this, url;
    if (self.options.path)
        url = self.options.path + '/';
    url += [pkg, language].join('-');

    return $.ajax ({
        url : url,
        dataType : "json",
        cache : self.options.cache
    }).promise();
}

function loadLanguages () {
    $.each(self.options.packages,function(i, pkg){
        getLanguage(pkg, language).then(resolveFunction());
    });

    return baseDfr.promise();                
}

function initialize(options) {
    packages = options.packages;
    count = options.packages.length;    

    return loadLanguages();
}

var options =  {
    packages : $('div')          
};

initialize(options).done(function(){
    // This will only be called when baseDfr.resolve() is called.
    console.log("Fired all getLanguage().");
});