【问题标题】:Managing Synchronous and Asynchronous JavaScript Functions with jQuery's Deferred使用 jQuery 的 Deferred 管理同步和异步 JavaScript 函数
【发布时间】:2013-12-04 19:49:19
【问题描述】:

我需要通过 Socket.IO(客户端)在 websocket 上运行一系列调用。因为我没有使用 $.ajax,所以 jQuery 的延迟函数也不会集成,我必须手动处理 Promise。对于每个 websocket 调用,我都会传递一个回调,我很快就会看到这个项目是如何失控的。这是我的 websocket 调用如何工作的简化示例(不包括所有连接处理代码):

function js2node(nodeFunction, data, callback){
    socket.emit('incoming', nodeFunction, data, callback);
}

function sampleServerCall(){
    js2node('sampleCall', 'something', 'sampleCallback');
}

function sampleCallback(json){
    // Handle data
}

sampleServerCall();

我将与服务器进行大量对话,所有调用都是异步的,但有些调用需要按特定顺序返回。输入 jQuery 延迟。这是一些工作代码:

var deferredArray = [];

$(function(){
    $.when(  // Any order
        getData1(),
        getData2()
    ).then(function(){  // Must have responses from dataCallback1 and dataCallback2 before doing this...
        $.when(  // Any order
            getData3(),
            getData4()
        ).then(function(){  // Must have responses from dataCallback3 and dataCallback4 before doing this...
            getData5();
        });
    });
});

function getData1(){
    js2node('data1', 'something', 'dataCallback1');
    deferredArray[0] = new $.Deferred();
    return deferredArray[0].promise();
}

function getData2(){
    js2node('data2', 'something', 'dataCallback2');
    deferredArray[1] = new $.Deferred();
    return deferredArray[1].promise();
}

function getData3(){
    js2node('data3', 'something', 'dataCallback3');
    deferredArray[2] = new $.Deferred();
    return deferredArray[2].promise();
}

function getData4(){
    js2node('data4', 'something', 'dataCallback4');
    deferredArray[3] = new $.Deferred();
    return deferredArray[3].promise();
}

function getData5(){
    js2node('data5', 'something', 'dataCallback5');
    deferredArray[4] = new $.Deferred();
    return deferredArray[4].promise();
}

function dataCallback1(json){
    // Handle data
    deferredArray[0].resolve();
}

function dataCallback2(json){
    // Handle data
    deferredArray[1].resolve();
}

function dataCallback3(json){
    // Handle data
    deferredArray[2].resolve();
}

function dataCallback4(json){
    // Handle data
    deferredArray[3].resolve();
}

function dataCallback5(json){
    // Handle data
    deferredArray[4].resolve();
}

如您所见,我仍然坚持使用 when/then 的嵌套回调方式,并且随着我添加功能,嵌套可能会更深入。 Deferred 对我来说是一个新概念,但我读过它应该在这种情况下有所帮助。我觉得必须有比我目前正在做的更好的方法。谁能帮我更有效地进行设置?

【问题讨论】:

  • 看看stackoverflow.com/a/20326123/461055,答案给出了如何按顺序执行延迟对象的例子。
  • @Sumit,谢谢,我将不得不玩一些。我想我从下面的答案中得到了我需要的东西,但这也应该有帮助!

标签: javascript jquery asynchronous jquery-deferred


【解决方案1】:

您可以使用 .then 做更多事情:

$(function(){
    $.when(
        doSock('data1', 'something'),
        doSock('data2', 'something')
    ).then(function(data1, data2){
        return $.when(
            doSock('data3', 'something'),
            doSock('data4', 'something')
        );
    }).then(function(data3, data4){
        return doSock('data5', 'something');
    });
});

这样你的嵌套永远不会比这更深。

(我使用了adeno的辅助方法)

【讨论】:

  • +1,确实,从 $.when 方法返回承诺是一种方法。
  • 太好了,这解决了嵌套问题,应该可以帮助团队更好地遵循我的意图!
  • 不幸的是,这没有按预期工作。第二个.then(data5)中的“doSock”调用在第二个$.when(data3和data4)中的函数实际给出解析之前执行。事实上,第二个.then函数(data3,data4)接收到的变量实际上是来自第一个.then函数(data1,data2)的相同数据!抱歉,我确定这会让人难以理解。
  • 它似乎对我有用,当我用 setTimeout 替换套接字请求时:jsfiddle.net/PpZkd
  • 啊,只需将.then 替换为.pipe。升级到 1.8 的时候别忘了回.thenjsfiddle.net/PpZkd/2
【解决方案2】:

使用更好的辅助函数肯定会有所帮助,但您仍然必须使用 $.when 和 $.then 来构造调用,以便以正确的顺序执行它们

function doSock(nodeFunction, data) {
    var def = new $.Deferred();
    socket.emit('incoming', nodeFunction, data, function(received) {
        def.resolve(received)
    });
    return def.promise();
}

$(function(){
    $.when(
        doSock('data1', 'something'),
        doSock('data2', 'something')
    ).then(function(data1, data2){
        $.when(
            doSock('data3', 'something'),
            doSock('data4', 'something')
        ).then(function(data3, data4){
            doSock('data5', 'something');
        });
    });
});

【讨论】:

  • 谢谢,帮助函数可以很好地清理大量冗余混乱!我肯定会结合使用您的答案和凯文的答案。尽管更好地清理了我的代码,但我认为我必须接受 Kevin's 来应对嵌套情况。 Grr,希望我能同时接受!非常感谢您的帮助。
  • 在实现这个之后,我确实有一个问题。根据“then”的第一个实例,是否有任何类型的保证变量“data1”将来自 doSock 调用“data1”?换句话说,我在 then 函数中定义的任何变量是否总是与我定义列出函数的顺序相同(不一定在它们完成时)?情况似乎是这样,但我只是想确保依赖该假设是安全的。
  • 是的,在 $.then 中作为参数返回的数据的顺序始终与 doSock 函数等的顺序相同。这样做是为了让您知道结果来自哪里,否则它会很难管理。
  • 好的,太好了。再次感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 2021-11-21
相关资源
最近更新 更多