0

Web ページの一連の非同期アクティビティにシリアル化されたロジックを強制しようとしています。jQuery deferred オブジェクトを使用したいのは確かですが、ユーザーがさまざまなボタンをクリックして選択を行うことを決定したときに、実行したい関数が依存しているという問題に遭遇します。次のjsFiddleアイデアを使用してこれを行うためのヘルプを探しています:

4 つのボタンのシーケンスを考えてみましょう。クリックすると、各ボタンが無効になり、次のボタンが有効になります。各ボタンは、有効になるまでイベントを設定しないでください。3 番目のボタンが有効になった後にのみ実行される追加のタスク (この場合はアラート) があります。

基本的な 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 から別の Promise に非同期でデータを取得する良い方法は、それらをpipeでチェーンすることですが、UI イベント内からタスクの完了をトリガーしたいので、以下に示すものよりも優れたものを想像するのに苦労しています。

これが最善の方法であるとは断言しませんが、これを処理するために私が考えることができる最も簡単な方法は、特定の約束と「タスク」を受け取り、新しい約束を作成し、タスクを許可するユーティリティ関数を作成することですpromise をどうするかを決定しますが、指定された promise が解決された後にのみ、新しい promise を返します。

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の完全なソース(あなたのものから変更されたもの)

于 2013-01-16T01:09:29.727 に答える
0

おそらく、時間のかかる一連のイベント用に設計されたキューを使用したいと思うでしょう。それらは動力源と同じシステムです$.animate。一度に実行される関数は 1 つだけであり、次の関数は、最初の関数が で終了したと明示的に言うまで実行されません$.dequeue

一方、Deferred は実際には、データが利用可能になった時点でデータを消費することを目的としています。

queuedequeueを参照してください。私が書いたこの他の最近の回答も参照してください。これには、コード例と jsfiddle があります。

于 2013-01-16T01:33:49.140 に答える
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 に答える