4

我正在使用延迟,因为我需要异步执行多个进程。

为了更清楚,这是我治疗的意义:

  • 处理1:调用提供用户权限的ajax服务
  • Treatment2 :调用提供链接和标签的 ajax 服务。

我需要同时调用这 2 个服务,然后得到这两个服务的统一响应,以便根据权限显示链接(我真正的问题是使用第 3 个 ajax 服务,但我们只讨论 2 个以简化)。

首先,我将 deferred 声明为 global var :

var treatment1 = $.Deferred();
var treatment2 = $.Deferred();

然后,当我需要完成这项工作时,我使用所需的数据调用 resolve 方法,以便在全局唯一处理中使用它:

  • 当我的第一个 ajax 服务响应时:treatment1.resolve(responseData1)
  • 当我的第二个 ajax 服务响应时:treatment2.resolve(responseData2)

当处理 1 和 2 完成时,触发 done 事件:

$.when(treatment1, treatment2).done(function(responseData1,responseData2) {
    DoGlobalTreatmentWithAllResponseData(responseData1,responseData2)
}

我的问题是 deferred 只能工作一次。

由于我的网站主要是用 ajax 实现的,所以我需要多次触发该事件。

用户可以单击按钮来搜索用户。然后显示用户列表,并异步调用 ajax 服务。这个操作可以无限重复。

我只需要一种方法来重用延迟但多次的原则。我知道这个问题已经讨论过了,每个人都说 deferred 不能这样工作。

但是,真的不可能重置延迟状态或重置承诺(即使通过实现自定义解决方案,使用 AOP 或其他方式)?

如果不可能,我可以使用什么解决方案?我不想一个接一个地触发治疗,但我真的想在所有治疗完成后(也就是说,在活动中的最后一次治疗结束后)做一个全局治疗,并且我想使用responseData每个服务的.

这是我想自定义的示例代码:http: //jsfiddle.net/PLce6/14/

我希望清楚,因为英语不是我的母语。

预先感谢您的帮助。

4

3 回答 3

3

延期只能解决/拒绝一次...但是,我认为问题在于您如何构建代码...

只要你每次都初始化你的 deferred ,这样做就没有任何问题......我认为问题是这样的:

首先,我将 deferred 声明为全局变量:

var treatment1 =$.Deferred(); 
var treatment2 = $.Deferred();

相反,您可以尝试在按钮单击中调用的函数中执行此操作吗

用户可以点击按钮搜索用户

所以有这样的功能:

function onClick() {
    var treatment1 =$.ajax({url: '/call1'}); 
    var treatment2 = $.ajax({url: '/call2'});
    $.when(treatment1, treatment2).done(function(obj1, obj2) {
            // do whatever else you need
    });
}

现在从您的帖子的其余部分来看,您似乎正在尝试重用延迟 - 但在这种情况下,您的原始解决方案不应该有保持延迟作为全局的问题,因为您的 done 将使用它们解决的任何数据调用.

您能否发布更多代码以帮助解释您要执行的操作。

从下面我自己的评论中更新以进行详细说明

基于 op 的小提琴,他希望能够多次触发相关动作。解决方案是让相关操作创建新的延迟并将 a$.when连接到自身。请参阅更新的小提琴http://jsfiddle.net/PLce6/15/

// global
var d1 = $.Deferred();
var d2 = $.Deferred();
var d3 = $.Deferred();

// here's the reset 
function resetDeferreds() {
d1 = $.Deferred();
d2 = $.Deferred();
d3 = $.Deferred();
$.when(d1, d2, d3).done(
    function (responseData1, responseData2, responseData3) {
       DoGlobalTreatmentWithAllResponseData(responseData1, responseData2, responseData3);
    resetDeferreds();
});

// the onclick handlers
function do3() {
d3.resolve('do3 ');
return d3;
}

// the top level $.when
$.when(d1, d2, d3).done(function (responseData1, responseData2, responseData3) {
    DoGlobalTreatmentWithAllResponseData(responseData1, responseData2, responseData3);
    resetDeferreds();
});
于 2013-11-14T16:41:49.333 回答
1

也许你的代码设计得不好?

我不明白这将是一个问题。异步进程应该负责Deferred每次都创建一个新对象。

function doSomething() {
    var d = $.Deferred();

    setTimeout(function () {
        d.resolve();
    }, 1000);

    return d;
}

function doSomethingElse() {
    var d = $.Deferred();

    setTimeout(function () {
        d.resolve();
    }, 1000);

    return d;
}

然后,您始终可以执行以下操作:

$.when(doSomething(), doSomethingElse()).done(function () {
    console.log('done');
});

总有解决办法:

如果您绝对需要能够resolve多次调用同一个Deferred,那么您应该将 包装Deferred到另一个对象中,比如说DeferredWrapper,这将公开与 a 相同的 API,Deferred但会将所有方法调用委托给它所封装的Deferred

除了委派函数调用之外,DeferredWrapper还必须跟踪对对象进行的所有侦听操作(例如,完成、始终、失败……)。可以将DeferredWrapper所有操作作为[functionName, arguments]元组存储在内部this._actions属性中。

最后,您需要为状态更改操作(例如,reject、resolve、resolveWith...等)提供一个特殊的实现,如下所示:

  1. d为 的内部Deferred引用this._deferred

  2. fn为被调用函数的函数名。

  3. 如果d.state()没有挂起

    3.1 做d = this._deferred = [[native jQuery Deferred]]

    3.2 对 应用所有操作d

  4. 返回结果d[fn].apply(d, arguments)

注意:您还需要实现自定义promise实现并确保其行为正确。您可能可以使用与描述的方法类似的方法。

于 2013-11-14T16:49:22.173 回答
0

我将建议一个小的改变。您不清楚的一个因素是每次治疗 1 和治疗 2 的结果是否不同。如果他们是那么做@raghu 和@juan-garcia

function onClick() {
    var treatment1 =$.ajax({url: '/call1'}); 
    var treatment2 = $.ajax({url: '/call2'});
    $.when(treatment1, treatment2).done(function(obj1, obj2) {
            // do whatever else you need
    });
}

如果他们不改变,那么这样做:

var treatment1 =$.ajax({url: '/call1'}); 
var treatment2 = $.ajax({url: '/call2'});

function onClick() {
    $.when(treatment1, treatment2).done(function(obj1, obj2) {
            // do whatever else you need
    });
}

或者它的一些变化。因为一旦它们完成,您的回调函数将始终立即执行。它仍然是异步的,但它不需要等待,因为一切都准备好了。这适用于两个用例。这是一种非常常见的数据模式,当在页面中绘制新组件时,可能需要几秒钟才能加载数据,然后才能在功能上发挥作用。这是一种非常有用的延迟加载机制。一旦它进入,尽管一切看起来都像是在瞬间做出反应。

我在 JSFiddle 上的示例中重新编写了 javascript,以仅显示我认为您需要查看的基础知识。那就是这里。鉴于您的示例,我认为错误在于认为必须多次调用 resolve 才能触发行为。调用 done 行为会提示一次性行为,并且每次调用 done 都会将新行为加载到队列中。Resolve 被调用一次。$.when().done() 你调用的次数与你有依赖于特定 when() 条件的行为一样多。

于 2013-11-14T16:50:11.380 回答