0

我正在尝试将序列化逻辑强制到网页上的一组异步活动上。我相当确定我想使用 jQuery 延迟对象,但我遇到了一个问题,即我想要执行的函数取决于用户何时决定通过单击各种按钮进行选择。我正在使用以下 jsFiddle 想法寻求帮助:

考虑一系列 4 个按钮。单击时,每个按钮都会禁用自身并启用下一个按钮。每个按钮在启用之前不应设置其事件。只有在启用第三个按钮后,才能完成一个附加任务(在这种情况下是一个警报)。

基本 HTML 代码

<button id="btn1">Click 1st</button>
<button id="btn2" disabled="disabled">Click 2nd</button>
<button id="btn3" disabled="disabled">Click 3rd</button>
<button id="btn4" disabled="disabled">Click 4th</button>

每个步骤中的任务

var fnDoStageOne = function() {
  $("#btn1").one("click", function(event, ui) {
    $("#btn1").prop("disabled", true);
    $("#btn2").prop("disabled", false);
    //STAGE ONE IS ONLY DONE AFTER THIS POINT
  });
};

var fnDoStageTwo = function() {
  $("#btn2").one("click", function(event, ui) {
    $("#btn2").prop("disabled", true);
    $("#btn3").prop("disabled", false);
    //STAGE TWO IS ONLY DONE AFTER THIS POINT
  });
};

var fnDoStageThree = function() {
  $("#btn3").one("click", function(event, ui) {
    $("#btn3").prop("disabled", true);
    $("#btn4").prop("disabled", false);
    //STAGE THREE IS ONLY DONE AFTER THIS POINT
  });
  alert("Shouldn't see this if button 3 isn't active yet");
};

var fnDoStageFour = function() {
  $("#btn4").one("click", function(event, ui) {
    $("#btn4").prop("disabled", true);
    alert("Task complete");
    //STAGE FOUR IS ONLY DONE AFTER THIS POINT
  });
};

不正确的控制逻辑

var oDeferredObj = $.Deferred();

oDeferredObj.then(fnDoStageOne);
oDeferredObj.then(fnDoStageTwo);
oDeferredObj.then(fnDoStageThree);
oDeferredObj.then(fnDoStageFour);
oDeferredObj.resolve();

jsfiddle可以在这里看到:http: //jsfiddle.net/sva79/

我最初的理解是,我可以使用 .then() 函数将函数链接到 deferred 中。显然,这不起作用,因为第 3 步中的附加任务会在页面加载时触发。我需要如何调整此场景的控制或逻辑以解决每个步骤,直到注册了相应的按钮按下?

4

3 回答 3

3

您的代码示例没有按照您的想法执行。您所做的只是添加到解决后直接要做的事情列表中oDeferredObj。此外,还存在解决任务何时真正“完成”的问题,您的代码并没有完全标记。

这似乎是我前段时间在另一个问题中解决过的问题,但我不确定我是否想要我当时给出的答案,所以让我重新尝试。

您正在寻找的是一种将的承诺链接在一起的方法。我想,您还想要一种方式来说明何时解决(或拒绝)承诺。

将数据从一个 Promise 异步获取到另一个 Promise 的一种好方法是用 链接它们pipe,但是由于您想从 UI 事件中触发任务的完成,我很难想象比我下面的内容更好的东西。

我不会发誓这是最好的方法,我能想到的最简单的处理方法是创建一个实用函数,它接受给定的承诺和“任务”,创建一个新的承诺,让你的任务决定如何处理承诺,但只有在给定的承诺解决后,并返回新的承诺。

var nextStage = function (promise, task) {
  var oDeferredObj = $.Deferred();
  promise.then(function () {
    task(oDeferredObj);
  });
  return oDeferredObj;
}

这可以用于将您的任务菊花链在一起:

/* Creation of deferred and initial wiring */
var p1;
var starterObj = $.Deferred();
p1 = starterObj;
p1 = nextStage(p1, fnDoStageOne);
p1 = nextStage(p1, fnDoStageTwo);
p1 = nextStage(p1, fnDoStageThree);
p1 = nextStage(p1, fnDoStageFour);
p1.done(function () {
  alert("All stages done.");
})
$("#start").one("click", function (event, ui) {
  //fire it up.
  $("#start").prop("disabled", true);
});

显然,你会想要做一些事情来表明某个特定的任务已经完成,例如:

var fnDoStageOne = function (promise) {
  //setup, etc.
  $("#btn1").one("click", function (event, ui) {
    //.. whatever needs to happen  in the ui.
    //STAGE ONE IS ONLY DONE AFTER THIS POINT
    promise.resolve();
  });
};

请注意,我只是在承诺成功时给了你一个开始。明智的做法是在他们失败时多做一点。此外,如果您想将数据从一个 Promise 传递到另一个 Promise,您可能希望需要pipe,等等。

jsFiddle 中的完整源代码(根据您的修改)here

于 2013-01-16T01:09:29.727 回答
0

我不明白你为什么需要延迟,但我知道你没有使用它们。

尝试这样的事情。

firstResolution  = $.Deferred();
secondResolution = $.Deferred();

function stepOne() {
   //disable button one
   //enable button two
   return firstResolution;
}

function stepTwo() {
    //disable button two
    //enable button three
}

$.when(stepOne()).then(stepTwo);

$.when(secondResolution).then(stepThree);

// This is also acceptable (and maybe better?)
// $.when(firstResolution, seconResolution).then(stepThree);

// when you resolve, then step two will fire.
firstResolution.resolve();

// and for stepThree to fire
secondResolution.resolve();
于 2013-01-15T23:55:25.710 回答
0

也许您想使用队列,它是为可能耗时的事件序列而设计的。他们是同一个系统,权力$.animate; 一次只执行一个函数,直到第一个明确表示它以$.dequeue.

另一方面,延迟实际上是在数据可用时使用数据。

请参阅queuedequeue。另请参阅我写的另一个最近的答案,其中包含示例代码和 jsfiddle。

于 2013-01-16T01:33:49.140 回答