41

据え置きをキャンセルしたい状況があります。deferred は ajax 呼び出しに関連付けられています。

deferred を使用する理由

$.ajax によって返される通常の xhr オブジェクトは使用しません。私は jsonp を使用しています。つまり、エラー処理に HTTP ステータス コードを使用できず、それらを応答に埋め込む必要があります。その後、コードが検査され、関連付けられた遅延オブジェクトが解決済みまたは拒否済みとしてマークされます。これを行うカスタム API 関数があります。

function api(options) {
  var url = settings('api') + options.url;
  var deferred = $.Deferred(function(){
    this.done(options.success);
    this.fail(options.error);
  });
  $.ajax({
    'url': url,
    'dataType':'jsonp',
    'data': (options.noAuth == true) ? options.data : $.extend(true, getAPICredentials(), options.data)
  }).success(function(jsonReturn){
    // Success
    if(hasStatus(jsonReturn, 'code', 200)) {
      deferred.resolveWith(this, [jsonReturn]);
    } 
    // Failure
    else {
      deferred.rejectWith(this, [jsonReturn]);
    }
  });

  return deferred;
}

延期をキャンセルしたい理由

リストのフィルターとして機能する入力フィールドがあり、入力が終了してから 0.5 秒後にリストが自動的に更新されます。一度に 2 つの ajax 呼び出しが未処理になる可能性があるため、前の呼び出しをキャンセルして、2 回目以降に返されず、古いデータが表示されないようにする必要があります。

気に入らない解決策

  • で添付されたハンドラが起動するため、遅延を拒否したくありません.fail()
  • ajaxが戻ったときに自動的に解決済みまたは拒否済みとしてマークされるため、無視できません。
  • 遅延オブジェクトを削除すると、ajax 呼び出しが戻り、遅延オブジェクトを解決済みまたは拒否済みとしてマークしようとすると、エラーが発生します。

私は何をすべきか?

遅延をキャンセルしたり、添付されたハンドラーを削除したりする方法はありますか?

設計を修正する方法についてのアドバイスは大歓迎ですが、ハンドラーを削除する方法や、ハンドラーが起動しないようにする方法を見つけることが優先されます。

4

4 に答える 4

17

jQuery のドキュメントとコードを見ると、延期された jQuery をキャンセルする方法がわかりません。

resolveWith代わりに、後続の ajax 呼び出しが既に起動されており、この ajax 呼び出しがその結果を無視する必要があることをハンドラーで知る方法がおそらく必要です。グローバルにインクリメントするカウンターでそれを行うことができます。ajax 呼び出しの開始時に、カウンターをインクリメントしてから、値をローカル変数に取得するか、ajax オブジェクトのプロパティとして設定します。resolveWithハンドラーで、カウンターが ajax 呼び出しの開始時と同じ値を保持しているかどうかを確認します。そうでない場合は、結果を無視します。存在する場合、新しい ajax 呼び出しは発生していないため、結果を処理できます。

別の方法として、既に実行中の ajax 呼び出しを拒否することもできるため、一度に複数の呼び出しが実行されることはありません。1 つが終了したら、その結果をそのまま使用するか、必要に応じて次の結果を起動することができます。

于 2012-07-17T21:56:57.083 に答える
7

必要に応じて deferred を「キャンセル」することはできませんが、単純なクロージャーを作成して、jqXHR オブジェクトを返す $.ajax を介して最後の ajax 呼び出しを追跡できます。これを行うことで、最後の jqXHR が終了していない場合に、新しい jqXHR が開始されたときに、単純に呼び出しを中止できます。あなたのコードの場合、それは jqXHR を拒否し、最初に望んでいたように、遅延を開いたままにして削除します。

var api = (function() {
    var jqXHR = null;

    return function(options) {
        var url = options.url;

        if (jqXHR && jqXHR.state() === 'pending') {
            //Calls any error / fail callbacks of jqXHR
            jqXHR.abort();
        }

        var deferred = $.Deferred(function() {
            this.done(options.success);
            this.fail(options.error);
        });

        jqXHR = $.ajax({
             url: url,
             data: options.toSend,
             dataType: 'jsonp'
        });

        jqXHR.done(function(data, textStatus, jqXHR) {
            if (data.f && data.f !== "false") {
                deferred.resolve();
            } else {
                deferred.reject();
            }
        });

        //http://api.jquery.com/deferred.promise/  
        //keeps deferred's state from being changed outside this scope      
        return deferred.promise();
    };
})();

これをjsfiddleに投稿しました。あなたがそれをテストしたい場合。Set timeout は jsfiddles delayer と組み合わせて使用​​され、通話の中断をシミュレートします。ログを表示するには、コンソール対応のブラウザが必要です。

ちなみに、.success()、.error()、および complete() メソッドを、遅延メソッド done()、fail()、および always() に切り替えます。jquery/ajax経由

非推奨の通知: jqXHR.success()、jqXHR.error()、および jqXHR.complete() コールバックは、jQuery 1.8 で非推奨になります。最終的な削除に備えてコードを準備するには、代わりに jqXHR.done()、jqXHR.fail()、および jqXHR.always() を使用してください。

于 2012-08-08T10:58:45.757 に答える
1

JustinY: あなたはすでに自分が望むものに本当に近づいているようですね. すでに 2 つの deferred を使用しています (inner-> ajax と outer -> $.Deferred())。次に、内部の deferred を使用して、いくつかの条件に基づいて外部の deferred を解決する方法を決定します。

ですから、したくない場合は、外側の deferred をまったく解決しないでください (おそらく、内側の dfd を解決/拒否できるようにするためのトグル ゲートとして機能するブール変数があるかもしれません)。この関数全体にアタッチしたハンドラーは起動しません。内部成功関数の例:

if(gateOpen){
  gateOpen = false;
  if(hasStatus(jsonReturn, 'code', 200)) {
    deferred.resolveWith(this, [jsonReturn]);
  }
  else {
    deferred.rejectWith(this, [jsonReturn]);
  }
}

アプリケーション内の他のロジックによって、gateOpen がいつ true に戻されるかが決定されます (ある種の _.throttle() または _.debounce() タイムアウト、ユーザー インタラクションなど、必要に応じて)。他のリクエストを追跡またはキャンセルしたい場合その関数のelseでも、それを行うことができます。しかし、基本的なことは、その外部遅延を解決または拒否する必要がないということです。そして、内側のものをキャンセル/中止しなくても、それをキャンセルするのと同じです。

于 2014-05-22T13:39:08.667 に答える