Javascript 为不同的处理程序向deferred.resolve()传递不同的参数

Javascript 为不同的处理程序向deferred.resolve()传递不同的参数,javascript,jquery,ajax,Javascript,Jquery,Ajax,我正在尝试使用jQuery.Deferrd对象同步多个ajax回调。显然jQuery.when会为您处理这个问题,但是我的代码的架构是,ajax请求不会在同一个方法中被调用。例如,这就是流程: //点击一个按钮 //模块1请求一段html并更新DOM //模块2请求一个不同的html片段并更新DOM 我需要两个模块同时更新DOM,这意味着我需要确保在两个请求都返回后运行回调 模块1和模块2需要能够彼此独立存在,并且彼此不了解,因此不能使用$.when(doMod1Request(),doMod2

我正在尝试使用jQuery.Deferrd对象同步多个ajax回调。显然jQuery.when会为您处理这个问题,但是我的代码的架构是,ajax请求不会在同一个方法中被调用。例如,这就是流程:

//点击一个按钮

//模块1请求一段html并更新DOM

//模块2请求一个不同的html片段并更新DOM

我需要两个模块同时更新DOM,这意味着我需要确保在两个请求都返回后运行回调

模块1和模块2需要能够彼此独立存在,并且彼此不了解,因此不能使用$.when(doMod1Request(),doMod2Request())一起发出请求。然后(function(){…})和回调也应该是独立的

因此,我围绕ajax编写了一个包装器,它将回调添加到延迟对象,并以类似的方式添加到$。当解析延迟对象时,ajax请求返回的次数与延迟对象上的回调次数相同

然而,我的困境被推迟了。resolve()只能用一组参数调用,因此每个回调函数都会得到相同的值

e、 g

var deferred=new$.deferred();
延迟。完成(功能(响应){
console.log(响应);//
});
延迟。完成(功能(响应){
console.log(响应);//
});
延期。决议(“”);
而我想要这样的东西:

var deferred = new $.Deferred();
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-1"></div>
});
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-2"></div>
});
deferred.resolve(['<div class="html-snippet-1"></div>', '<div class="html-snippet-2"></div>']);
$("myButton").on('click', function(){
    var snippets = [];
    var promises_1 = MODULE_1.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_1"),
            response: response
        });
    });
    var promise_2 = MODULE_2.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_2"),
            response: response
        });
    });
    $.when(promise_1, promise_2).done(function() {
        $.each(snippets, function(i, snippetObj) {
            snippetObj.target.html(snippetObj.response);
        });
    });
});
$(function(){
    $("myButton").on('click', function(){
        var promises = [];
        var snippets = [];
        var modules = [MODULE_1, MODULE_2, MODULE_3 .....];
        for (var i=1; i<=10; i++) {
            promises.push(modules[i].getSnippet().done(function(response){
                snippets.push({
                    target: $("#div_" + i),
                    response: response
                };
            }));
        }
        $.when.apply(this, promises).done(function() {
            $.each(snippets, function(i, snippetObj) {
                snippetObj.target.html(snippetObj.response);
            });
        });
    });
});
var deferred=new$.deferred();
延迟。完成(功能(响应){
console.log(响应);//
});
延迟。完成(功能(响应){
console.log(响应);//
});
延期。决议(['',]);

这是可能的还是我做得不对?

让我们假设您的模块看起来像这样:

var MODULE_1 = function() {
    function getSnippet() {
        return $.ajax({
            //ajax options here
        });
    }

    return {
        getSnippet: getSnippet
    }
}();

var MODULE_2 = function() {
    function getSnippet() {
        return $.ajax({
            //ajax options here
        });
    }

    return {
        getSnippet: getSnippet
    }
}();
如果模块不同,不要担心,重要的是getSnippet函数每个都返回一个jqXHR对象,该对象(从jQuery1.5开始)实现Promise接口

现在,假设您希望获取这两个代码片段以响应某个事件(例如,单击按钮),并在收到两个ajax响应后执行某些操作,那么单击处理程序将如下所示:

var deferred = new $.Deferred();
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-1"></div>
});
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-2"></div>
});
deferred.resolve(['<div class="html-snippet-1"></div>', '<div class="html-snippet-2"></div>']);
$("myButton").on('click', function(){
    var snippets = [];
    var promises_1 = MODULE_1.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_1"),
            response: response
        });
    });
    var promise_2 = MODULE_2.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_2"),
            response: response
        });
    });
    $.when(promise_1, promise_2).done(function() {
        $.each(snippets, function(i, snippetObj) {
            snippetObj.target.html(snippetObj.response);
        });
    });
});
$(function(){
    $("myButton").on('click', function(){
        var promises = [];
        var snippets = [];
        var modules = [MODULE_1, MODULE_2, MODULE_3 .....];
        for (var i=1; i<=10; i++) {
            promises.push(modules[i].getSnippet().done(function(response){
                snippets.push({
                    target: $("#div_" + i),
                    response: response
                };
            }));
        }
        $.when.apply(this, promises).done(function() {
            $.each(snippets, function(i, snippetObj) {
                snippetObj.target.html(snippetObj.response);
            });
        });
    });
});
如果您有许多构造类似的模块来获取许多代码段,则会稍微复杂一些,更好一些,如下所示:

var deferred = new $.Deferred();
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-1"></div>
});
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-2"></div>
});
deferred.resolve(['<div class="html-snippet-1"></div>', '<div class="html-snippet-2"></div>']);
$("myButton").on('click', function(){
    var snippets = [];
    var promises_1 = MODULE_1.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_1"),
            response: response
        });
    });
    var promise_2 = MODULE_2.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_2"),
            response: response
        });
    });
    $.when(promise_1, promise_2).done(function() {
        $.each(snippets, function(i, snippetObj) {
            snippetObj.target.html(snippetObj.response);
        });
    });
});
$(function(){
    $("myButton").on('click', function(){
        var promises = [];
        var snippets = [];
        var modules = [MODULE_1, MODULE_2, MODULE_3 .....];
        for (var i=1; i<=10; i++) {
            promises.push(modules[i].getSnippet().done(function(response){
                snippets.push({
                    target: $("#div_" + i),
                    response: response
                };
            }));
        }
        $.when.apply(this, promises).done(function() {
            $.each(snippets, function(i, snippetObj) {
                snippetObj.target.html(snippetObj.response);
            });
        });
    });
});
$(函数(){
$(“myButton”)。在('单击',函数()上{
var承诺=[];
var片段=[];
var modules=[模_1、模_2、模_3….];

对于(var i=1;i让我们假设您的模块如下所示:

var MODULE_1 = function() {
    function getSnippet() {
        return $.ajax({
            //ajax options here
        });
    }

    return {
        getSnippet: getSnippet
    }
}();

var MODULE_2 = function() {
    function getSnippet() {
        return $.ajax({
            //ajax options here
        });
    }

    return {
        getSnippet: getSnippet
    }
}();
如果模块不同,不要担心,重要的是getSnippet函数每个都返回一个jqXHR对象,该对象(从jQuery1.5开始)实现Promise接口

现在,假设您希望获取这两个代码片段以响应某个事件(例如,单击按钮),并在收到两个ajax响应后执行某些操作,那么单击处理程序将如下所示:

var deferred = new $.Deferred();
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-1"></div>
});
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-2"></div>
});
deferred.resolve(['<div class="html-snippet-1"></div>', '<div class="html-snippet-2"></div>']);
$("myButton").on('click', function(){
    var snippets = [];
    var promises_1 = MODULE_1.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_1"),
            response: response
        });
    });
    var promise_2 = MODULE_2.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_2"),
            response: response
        });
    });
    $.when(promise_1, promise_2).done(function() {
        $.each(snippets, function(i, snippetObj) {
            snippetObj.target.html(snippetObj.response);
        });
    });
});
$(function(){
    $("myButton").on('click', function(){
        var promises = [];
        var snippets = [];
        var modules = [MODULE_1, MODULE_2, MODULE_3 .....];
        for (var i=1; i<=10; i++) {
            promises.push(modules[i].getSnippet().done(function(response){
                snippets.push({
                    target: $("#div_" + i),
                    response: response
                };
            }));
        }
        $.when.apply(this, promises).done(function() {
            $.each(snippets, function(i, snippetObj) {
                snippetObj.target.html(snippetObj.response);
            });
        });
    });
});
如果您有许多构造类似的模块来获取许多代码段,则会稍微复杂一些,更好一些,如下所示:

var deferred = new $.Deferred();
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-1"></div>
});
deferred.done(function (response) {
    console.log(response); // <div class="html-snippet-2"></div>
});
deferred.resolve(['<div class="html-snippet-1"></div>', '<div class="html-snippet-2"></div>']);
$("myButton").on('click', function(){
    var snippets = [];
    var promises_1 = MODULE_1.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_1"),
            response: response
        });
    });
    var promise_2 = MODULE_2.getSnippet().done(function(response){
        snippets.push({
            target: $("#div_2"),
            response: response
        });
    });
    $.when(promise_1, promise_2).done(function() {
        $.each(snippets, function(i, snippetObj) {
            snippetObj.target.html(snippetObj.response);
        });
    });
});
$(function(){
    $("myButton").on('click', function(){
        var promises = [];
        var snippets = [];
        var modules = [MODULE_1, MODULE_2, MODULE_3 .....];
        for (var i=1; i<=10; i++) {
            promises.push(modules[i].getSnippet().done(function(response){
                snippets.push({
                    target: $("#div_" + i),
                    response: response
                };
            }));
        }
        $.when.apply(this, promises).done(function() {
            $.each(snippets, function(i, snippetObj) {
                snippetObj.target.html(snippetObj.response);
            });
        });
    });
});
$(函数(){
$(“myButton”)。在('单击',函数()上{
var承诺=[];
var片段=[];
var modules=[模_1、模_2、模_3….];

对于(var i=1;i我认为这是完全有效的。假设您有独立的模块,您可以这样做(有两个承诺):

现在,如果您想同时执行更新,并且仅当两个请求都成功时,只需编写

$.when(doMod1Request(), doMod2Request()).done(function(mod1result, mod2result) {
    doMod1Update(mod1result);
    doMod2Update(mod2result);
});
如果使用多个参数调用resolve函数,这只会变得很糟糕,因为jQuery在这方面有点不一致,并且不能真正区分多个参数和一个数组参数

要将它们与您正在使用的发布-订阅模式断开耦合,我建议如下:

function Combination() {
    this.deferreds = [];
    this.success = [];
    this.error = [];
}
Combination.prototype.add = function(def, suc, err) {
    this.deffereds.push(def);
    this.success.push(suc);
    this.error.push(err);
};
Combination.prototype.start = function() {
    var that = this;
    return $.when.apply($, this.deferreds).always(function() {
         for (var i=0; i<that.deferreds.length; i++)
             that.deferreds[i].done(that.success[i]).fail(that.error[i]);
         // of course we could also call them directly with the arguments[i]
    });
};

// Then do
var comb = new Combination();
window.notifyModules("something happened", comb); // get deferreds and handlers
comb.start();

// and in each module
window.listen("something happended", function(c) {
    c.add(doRequest(), doUpdate, doErrorHandling);
});
var guid = 0,
    deferreds = [];

window.request = function (url, deferred, success) {
    var requestId = guid++;

    if ($.inArray(deferred) === -1) {
        deferreds.push(deferred);
        $.extend(deferred, {
            requestCount: 0,
            responseCount: 0,
            args: {}
        });
    }

    deferred.requestCount++;

    deferred
        .done(function () {
            // Corresponding arguments are passed into success callback using requestId
            // which is unique to each request.
            success.apply(this, deferred.args[requestId]);
        });

    $.ajax(url, {
        success: function () {
            // Store arguments on deferrds args obj.
            deferred.args[requestId] = arguments;

            deferred.responseCount++;
            if (deferred.requestCount === deferred.responseCount) {
                deferred.resolveWith(this);
            }
        } 
    });
};
函数组合(){
这个。延迟=[];
this.success=[];
this.error=[];
}
composition.prototype.add=函数(def、suc、err){
此.deffereds.push(def);
这个。成功。推动(suc);
这个.error.push(err);
};
composition.prototype.start=函数(){
var=这个;
返回$.when.apply($,this.deferreds).always(函数(){

对于(var i=0;i我认为这是完全有效的。假设您有独立的模块,您可以这样做(有两个承诺):

现在,如果您想同时执行更新,并且仅当两个请求都成功时,只需编写

$.when(doMod1Request(), doMod2Request()).done(function(mod1result, mod2result) {
    doMod1Update(mod1result);
    doMod2Update(mod2result);
});
如果使用多个参数调用resolve函数,这只会变得很糟糕,因为jQuery在这方面有点不一致,并且不能真正区分多个参数和一个数组参数

要将它们与您正在使用的发布-订阅模式断开耦合,我建议如下:

function Combination() {
    this.deferreds = [];
    this.success = [];
    this.error = [];
}
Combination.prototype.add = function(def, suc, err) {
    this.deffereds.push(def);
    this.success.push(suc);
    this.error.push(err);
};
Combination.prototype.start = function() {
    var that = this;
    return $.when.apply($, this.deferreds).always(function() {
         for (var i=0; i<that.deferreds.length; i++)
             that.deferreds[i].done(that.success[i]).fail(that.error[i]);
         // of course we could also call them directly with the arguments[i]
    });
};

// Then do
var comb = new Combination();
window.notifyModules("something happened", comb); // get deferreds and handlers
comb.start();

// and in each module
window.listen("something happended", function(c) {
    c.add(doRequest(), doUpdate, doErrorHandling);
});
var guid = 0,
    deferreds = [];

window.request = function (url, deferred, success) {
    var requestId = guid++;

    if ($.inArray(deferred) === -1) {
        deferreds.push(deferred);
        $.extend(deferred, {
            requestCount: 0,
            responseCount: 0,
            args: {}
        });
    }

    deferred.requestCount++;

    deferred
        .done(function () {
            // Corresponding arguments are passed into success callback using requestId
            // which is unique to each request.
            success.apply(this, deferred.args[requestId]);
        });

    $.ajax(url, {
        success: function () {
            // Store arguments on deferrds args obj.
            deferred.args[requestId] = arguments;

            deferred.responseCount++;
            if (deferred.requestCount === deferred.responseCount) {
                deferred.resolveWith(this);
            }
        } 
    });
};
函数组合(){
这个。延迟=[];
this.success=[];
this.error=[];
}
composition.prototype.add=函数(def、suc、err){
此.deffereds.push(def);
这个。成功。推动(suc);
这个.error.push(err);
};
composition.prototype.start=函数(){
var=这个;
返回$.when.apply($,this.deferreds).always(函数(){

对于(var i=0;i,为了确保每个回调都传递了相应的参数,我已经执行了以下操作:

function Combination() {
    this.deferreds = [];
    this.success = [];
    this.error = [];
}
Combination.prototype.add = function(def, suc, err) {
    this.deffereds.push(def);
    this.success.push(suc);
    this.error.push(err);
};
Combination.prototype.start = function() {
    var that = this;
    return $.when.apply($, this.deferreds).always(function() {
         for (var i=0; i<that.deferreds.length; i++)
             that.deferreds[i].done(that.success[i]).fail(that.error[i]);
         // of course we could also call them directly with the arguments[i]
    });
};

// Then do
var comb = new Combination();
window.notifyModules("something happened", comb); // get deferreds and handlers
comb.start();

// and in each module
window.listen("something happended", function(c) {
    c.add(doRequest(), doUpdate, doErrorHandling);
});
var guid = 0,
    deferreds = [];

window.request = function (url, deferred, success) {
    var requestId = guid++;

    if ($.inArray(deferred) === -1) {
        deferreds.push(deferred);
        $.extend(deferred, {
            requestCount: 0,
            responseCount: 0,
            args: {}
        });
    }

    deferred.requestCount++;

    deferred
        .done(function () {
            // Corresponding arguments are passed into success callback using requestId
            // which is unique to each request.
            success.apply(this, deferred.args[requestId]);
        });

    $.ajax(url, {
        success: function () {
            // Store arguments on deferrds args obj.
            deferred.args[requestId] = arguments;

            deferred.responseCount++;
            if (deferred.requestCount === deferred.responseCount) {
                deferred.resolveWith(this);
            }
        } 
    });
};
因此,参数通过闭包进行管理。这使我能够确保两个模块互不了解,并且在另一个模块不存在时不会中断,例如:

var MODULE_1 = function () {
    $(".myButton").on('click', function() {
        // Cross module communication is achieved through notifications.
        // Pass along a new deferred object with notification for use in window.request
        window.notify('my-button-clicked', new $.Deferred);
    });
}();

var MODULE_2 = function () {
    // run get snippet when 'my-button-clicked' notification is fired
    window.listen('my-button-clicked', getSnippet);

    function getSnippet (deferred) {
        window.request('/module2', deferred, function () {
            console.log('module2 success');
        });
    }
}();

var MODULE_3 = function () {
    // run get snippet when 'my-button-clicked' notification is fired
    window.listen('my-button-clicked', getSnippet);

    function getSnippet (deferred) {
        window.request('/module3', deferred, function () {
            console.log('module3 success');
        });
    }
}();
以上允许每个模块独立运行,这意味着一个模块将在没有另一个模块的情况下工作,而另一个模块将松散地耦合代码,因为
模块2
模块3
都将相同的延迟对象传递到
窗口。请求
两个请求成功返回后,它们将得到解决

这是我的最终实施:

到e