2016-04-15 8 views
0

oResにプライマリソース(getData1())から来る可能性がある場合にのみ実行するイベントハンドラを$someElにバインドしました。 )またはバックアップ元(getData2())。プライマリソースがタイムアウトした場合にのみ、バックアップソースからデータが要求されます。

プライマリソースがタイムアウトしない場合、すべてが機能します。ただし、バックアップgetData2()関数が呼び出されると、dfdは解決されないため、$someElをクリックするとログに記録されることはありません。 getData2()のDeferredオブジェクトが$someElクリックハンドラが参照している変数dfdを上書きしているため、動作していないと思われます。

私は「ベストプラクティス」パターンを使用してDeferred/Promiseを適用していないと感じています。このシナリオでは、タイムアウト後にクリックハンドラがプライマリAJAXレスポンスまたはセカンダリAJAXレスポンスのいずれかからoResが移入されるのを適切に待つようにしますか?

明確化のためのいくつかの注意は:

  • getData1()は、文書は、文書のロード時にいつでも発射するので、イベントハンドラは$(document).ready()
  • の外で定義する必要があり $someEl.click()
  • 準備ができているだけで後に実行する必要があります
  • 私はここでのjQuery 1.7.1

とこだわっているコードです:

var oRes, dfd; 

// Get data from primary source 
function getData1() { 
    dfd = $.ajax({ 
    ... 
    success: function(data) { 
     oRes = data; 
    }, 
    error: function(jqXHR, textStatus, errorThrown) { 
     if (textStatus==='timeout') getData2(); 
    }, 
    timeout: 10000 // 10-second timeout 
    }); 
} 

// Get data from backup source 
function getData2() { 
    dfd = $.ajax({...}); 
} 

$someEl.click(function() { 
    dfd.done(function() { 
    console.log('This should only log when oRes is ready'); 
    }); 
}); 

$(document).ready(function() { 
    getData1(); 
}); 

私はこのペンで私の状況をシミュレートしました。基本的にhttp://codepen.io/thdoan/pen/pyVyKj

、私が出力するイベントハンドラを取得し、トラブルを抱えている「データが準備ができています!」 oResが入力されたときに、ページがロードされた後に手動でボックスをクリックする必要はありません。

+1

はちょうどあなたの現在の戦略では、$ someElがクリックされるたびに、それは繰延オブジェクトに別のコールバックを結合することを指摘したかったので、とき最終的に遅延が解決され、コールバックがX回実行されます.Xは要素がクリックされた回数です。これはあなたが望む行動かもしれませんが、あなたが気づいていることを確認したかっただけです。 –

+0

@MattDiamondそれを指摘してくれてありがとう、非常に良い点:)。代わりに '.one( 'click'、...)'を使うようにコードを変更しました。 – 10basetom

答えて

0

私はあなたがそれを1つのレベルまで持ち上げる必要があると思います。

クリックハンドラがリッスンする遅延インスタンスを作成します(インスタンスは変更されません)。

その後、getData1()またはgetData2()のいずれかから延期することを解決:

var oRes, 

    // Resolve this deferred when data has been successfully loaded: 
    dfd = $.Deferred(), 

    // But add listeners to this promise: 
    dfdPromise = dfd.promise(); 

// Get data from primary source 
function getData1() { 
    $.ajax({ 
     ... 
     success: function(data) { 
      oRes = data; 

      // Resolve when data loaded: 
      dfd.resolve(data); 
     }, 
     error: function(jqXHR, textStatus, errorThrown) { 
      if (textStatus==='timeout') getData2(); 
     }, 
     timeout: 10000 // 10-second timeout 
    }); 
} 

// Get data from backup source 
function getData2() { 
    $.ajax({...}) 
     .then(function(data){ 
      // Fallback data resolve: 
      dfd.resolve(data); 
     }); 
} 

$someEl.click(function() { 
    dfdPromise.done(function() { 
     console.log('This should only log when oRes is ready'); 
    }); 
}); 

$(document).ready(function() { 
    getData1(); 
}); 
+0

ありがとうSly_cardinal、あなたの解決策は働いた。これは私が乗り越えるために必要な精神病でした:-)。ここにcodepenがあります:http://codepen.io/thdoan/pen/zqjBvp – 10basetom

+0

それはまた、約束なしで働いたことに注意してください。 – 10basetom

0

私はajaxリクエストのコールバック内に関数呼び出しを含めます。

var oRes = null; 
var dfd = null; 

// Get data from backup source 
function getData2() { 
    dfd = $.ajax({...}); 
} 

// Get the primary data source 
function getData1() { 
    dfd = $.ajax({ 
    success: function(data) { 
     oRes = data; 

     // set the click handler when oRes is successfully set 
     $(someEl).click(function() { 
      console.log('This should only log when oRes is ready'); 
     }); 
    }, 
    error: function(jqXHR, textStatus, errorThrown) { 
     if (textStatus==='timeout') getData2(); 
    }, 
    always: function(){ 
     if (oRes==null){ 
      getData2(); 
     } 
    } 
    timeout: 10000 // 10-second timeout 
    }); 
} 
+0

残念ながら私は残念ながら、$ someEl *が '$(document).ready'より前にクリックされる可能性のあるより大きなアプリケーションの一部であるコードを扱っているので、そのイベントハンドラはその外部で定義する必要があります従って 'getData1()'の外側)にあります。明快さを加えるために質問を編集します。 – 10basetom

+0

JavaScriptがロードされた後にclickイベントが割り当てられるため、問題はありません。 DOMが完了せずにユーザーがクリックすると、すべてがロードされたことを確認した後、再度試行する可能性が高くなります。 – chriswirz

+0

chriswirz、私はこのペンの私の状況をシミュレートしました:http://codepen.io/thdoan/pen/pyVyKj - 問題の要点は、最初の負荷でボックスをクリックする必要があるということですその約束は尊重されないか、何か他のものが最初のログをブロックしています。私がしたいのは、oDataにデータが入力されると、イベントハンドラのメッセージに「Data is ready!」と表示されるはずです。手動でボックスをクリックする必要はありません。 – 10basetom

関連する問題