0

我正在开发一个 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返回一个承诺,一旦所有函数都被调用,该承诺就会被解决。

4

2 回答 2

2

I know you accepted an answer already but there is a much simpler way: use $.when.

function loadLanguages () {
    return $.when.apply( $, $.map( self.options.packages, function( pkg ) {
        return getLanguage(pkg, language);
    }) );
}
于 2012-04-20T05:40:44.233 回答
0

要解决此问题,您可以创建一个虚拟 Deferrer (baseDfr) 并将虚拟作为initialize(). 这里的想法是baseDfr.resolve()在所有getLanguage()调用完成后调用。我们使用计数器跟踪getLanguage()完成的调用次数。当计数器达到 0 时,我们调用baseDfr.resolve(). 我们知道何时使用返回的 deferrer by 上的or方法getLanguage()完成调用。then()done()$.ajax

The code to solve this can be found below. Also, a working example (on some divs) can be found here: http://jsfiddle.net/c5NBr/. Open your console to see the messages appear in correct order.

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().");
});
于 2012-04-15T21:02:33.020 回答