2016-05-09 5 views
0

ユーザーがブラウザで入力中にライブサーバー側の検索を実行しています。私のseach機能はタイピングペースに追いついていないので、リクエストが積み重なってしまいます。サーバが以前のリクエストを処理している間にajaxリクエストをキューに入れる方法は?

サーバーが応答する準備が整う前に、新しいクエリで置き換えられたクエリを取り消したいと思っています。

これは私が達成したいものです。

  • 最初のキーストロークをサーバーに送信する必要があります。
  • 次のキーストロークは、サーバーが最初のクエリに応答するまでクライアント側のスクリプトによってキューに入れられます。
  • その間に別のキーストロークが発生した場合、現在キューに入れられているキーストロークを置き換える必要があります。

このようにして、サーバーが準備ができたら、直前のキーストロークのみがサーバーに送信されます。もちろん、キューがない場合は、キーストロークをサーバーにまっすぐに送るだけです。

私の現在の実装では死んでシンプルです:

$.ajax({ 
    type: "get", 
    dataType: "script", 
    data: { 
    search: "something" 
    }, 
    url: "/api/search", 
    success: function(data, status, xhr) {}, 
    error: function(xhr, textStatus, errorThrown) {} 
}); 

答えて

2

私はあなたのアプローチを使用すると、各キーストローク上のサーバにリクエストを送信しているので、サーバーをあふれさせるために起こっていると思います。 @SravanSが言ったようにクライアント側でリクエストを中止したとしても、サーバーは引き続きこれらのすべてを処理し始めます。一度送信されたHTTPリクエストは既にネット上にありますが、止めることはできません。クライアント側では中止する必要はありません。サーバーに通知するか、送信したレスポンスを無視するだけですが、それ。

ユーザーが入力をやめたことを認識するための遅延を実装するのが最善の方法でしょう。これはジェネリック遅延イベントハンドラファクトリです。本当に使いやすく、関数を渡して遅延を割り当てるだけです。キーストロークの間にXミリ秒が経過した場合、リクエストが送信されますが、その遅延の前に別のキーストロークが発生した場合でも、リクエストはしません。

function delayedEvent(eventHandler, delay) { 
    var lastTimeout = null; 

    return function() { 
     var that = this, 
      args= Array.prototype.slice.call(arguments).sort(); 

     if (lastTimeout !== null) 
      window.clearTimeout(lastTimeout); 

     lastTimeout = window.setTimeout(function() { 
      eventHandler.apply(that, args); 
     }, delay); 
    }; 
} 

$('... selector ...').on('event', delayedEvent(function() { ... your code ... }, 500)); 

EDIT:これはキューを実装する方法ですが、私は出発点としてそれを使用し、このコードをテストしていません。

function eventQueue(requestMaker) { 
    // Here we store the last event queued, it'll wait until all the already running events are done. 
    var lastQueued = null, 
     runningQueue = []; 

    // Push a new event into the running queue 
    function pushRunning(toPush) { 
     runningQueue.push(toPush.done(
      // It is necesary to use an IIFE to get the index by value and not by reference 
      (function (index) { 
       return function() { 
        // Remove this event from the runningqueue 
        runningQueue.splice(index, 1); 
        // If the queue has been completed, start running the last event sent 
        if (lastQueued !== null && runningQueue.length === 0) { 
         pushRunning(lastQueued()); 
        } 
       } 
      }(runningQueue.lenght)); 
     )); 
    } 

    return function() { 
     var that = this, 
      args = Array.prototype.slice.call(arguments).sort(); 

     // Some events are already running, just override the lastQueued 
     if (runningQueue.length > 0) { 
      lastQueued = requestMaker.bind(that, args); 
     } else { 
     // Nothing queued run this event straight away, and queue it as running 
      pushRunning(requestMaker.apply(that, args)); 
     } 
    }; 
} 

$('... selector ...').on('event', eventQueue(function() { 
    // It's extremely important that you return the jquery $.ajax Promise 
    return $.ajax(...); 
}, 500)); 
+0

ありがとう、しかし、私はクライアント側でキューを処理したいだけ明確にする。したがって、キーストロークのいくつかは決してサーバーに送信されません。以前のキーストロークがサーバー側で処理されている間に最後に行われたキーストロークのみがクライアント側から送信される必要があります。 – ChristofferJoergensen

+0

申し訳ありませんが、いくつかのことは私に感動しません。あなたの質問では、要求を待ち行列に入れたいとし、キーストロークが起きたときにその要求を待ち行列の最初の位置に入れてください。最後のキューをキューの最上部に置いても、最初の要求は前に到着しますが、それは意味をなさないので、それを行うことで何も得られません。また、あなたのコメントでは、サーバーがすでにリクエストを処理している最中に、最後のキーストロークをクライアントから送信しないように言っていますか?あなたが最後のものを送ったなら、それはすでに何かを処理していますか?それは私の答えなんです。 –

+0

** 1)** 'キーストローク1 'が発生し、'要求a'を引き起こす** 2)** 'キーストローク2'は起こるが、'応答a 'がまだ発生していないのでキューに入れられる** 3)** 'キーストローク3 'が発生し、キュー内の ''キーストローク2' 'を置き換える。** 4) '応答a'が発生するので、 'キーストローク3'を含む'要求b 'がトリガされる。 – ChristofferJoergensen

0
var req = $.ajax(); 

//kill the request 
req.abort() 

あなたがリクエストを殺すために$ .ajax.abortメソッドを使用することができます。各キーを押すたびに、以前の要求があればそれを強制終了します。

var prevReq = {}; 
elem.onkeyup = function(){ 
    if(prevReq.abort) 
     prevReq.abort();  
    var prevReq = $.ajax(/*make the api call and clear prevReq object on response*/);  
}; 
+0

この回答に感謝します。しかし、私が言うことができる限り、これは要求を中止するだけで、要求をキューに入れません。したがって、以前の要求が保留されている間に別のキーストロークが発生した場合、それは中止されます。最新の要求のみを含むことができるキューに入れておく必要があります。 – ChristofferJoergensen

0
var arr = [], // bufor 
    flag = true; 
window.onkeydown = function (e) { 
    arr.push(e); 
    sync(); 
} 

function sync() { 
if(flag){ 
    flag = false; 
    sendAjax(arr.shift()); 
    } 
setTimeout(function() { 
    sync(); 
}, 40) 
} 

しかしsendAjaxでそのような何か:

.onSuccess = function() {flag = true;} 
.onError = function() {flag = true;} 

それはかなり原始的ですが、あなたはそれを開発することができますが、それはこの段階で、機能よりもかなり弾力性があります。

「しかし、それは動作し、仕事の事 - 愚かなアレント」:)

関連する問題