web-dev-qa-db-ja.com

ロングポーリングはJavaScriptでどのように機能しますか?

こんにちは、ロングポーリングでは、サーバーからの応答を受け取るまでサーバーとの接続を開いたままにし、再度ポーリングして次の応答を待つことを理解しています。しかし、私はそれをコーディングする方法を理解していないようです。長いポーリングを使用する以下のコードがありますが、私はそれを取得していないようです

(function poll(){
$.ajax({ url: "server", success: function(data){
   //update page based on data

}, dataType: "json", complete: poll, timeout: 30000 });
})();

しかし、どのようにして接続はここで開いたままにされますか。サーバーからの応答が得られると「ポーリング」機能が再び起動されることを理解していますが、接続はどのように開いたままにされますか?

Edit1:-誰かがここでタイムアウトが実際に何をするかを説明することもできれば素晴らしいでしょう

15
Rasmus

クライアントはサーバーに接続を開いたままにすることを強制することはできません。 serverは単に接続を閉じていません。サーバーはある時点で言う必要があります"それだけです。これ以上コンテンツはありません。さようなら"。ロングポーリングでは、サーバーは単純にそれを行わず、クライアントが追加のデータを待機し続けるようにします。更新が行われると、サーバーは少しずつだまされます。それがロングポーリングです。

クライアント側では、リクエストが終了していない間に、すでに受信したデータを時々チェックすることが可能です。これにより、サーバーから同じオープン接続を介してデータが送信される場合があります。あなたの場合、これは行われていません。successコールバックは、リクエストが完了したときにのみ起動します。これは基本的に、サーバーがクライアントをイベントの待機状態に保ち、このイベントに関するデータを送信し、接続を閉じる、ロングポーリングの安価な形式です。クライアントはそれをトリガーとして、データを処理し、サーバーに再接続して次のイベントを待ちます。

13
deceze

これを理解するのに混乱しているのは、議論がクライアント側のプログラミングに焦点を合わせているということです。

ロングポーリングは厳密にはクライアント側のパターンではありませんが、接続を開いたままにするためにWebサーバーが必要です。

背景:クライアントは、何かが発生したときや利用可能なときにWebサーバーから通知を受けたいと考えています。たとえば、新しいメールが届いたら、数秒おきに戻る必要はありません。

  1. クライアントは、Webサーバー上の特定のURLへの接続を開きます。
  2. サーバーは接続を受け入れ、ソケットを開き、この接続を処理するサーバー側コード(Javaのサーブレットまたはjsp、RoRまたはノード/エクスプレスのルートなど)に制御をディスパッチします。
  3. サーバーコードは、イベントまたは情報が利用可能になるまで待機します。たとえば、メールが届いたときに、「待機中の接続」のいずれかが特定の受信トレイに関するものかどうかを確認します。正しい場合は、適切なデータで応答します。
  4. クライアントはデータを受信し、その処理を実行してから、ポーリングの別の要求を開始します。
9
Brandon

すぐに戻ってくるが、最後のいくつかの結果は10〜15秒後に戻ってくるような、スタッガードデータの結果で何かをしようとしていました。簡単なjQueryハックを作成しましたが、それは私が望むことをやっていることです(それを使用することが理にかなっているかどうかはまだわかりません)。

(function($) {
    if (typeof $ !== 'function') return;
    $.longPull = function(args) {
        var opts = $.extend({ method:'GET', onupdate:null, onerror:null, delimiter:'\n', timeout:0}, args || {});
        opts.index = 0;
        var req = $.ajaxSettings.xhr();
        req.open(opts.method, opts.url, true);
        req.timeout = opts.timeout;
        req.onabort = opts.onabort || null;
        req.onerror = opts.onerror || null;
        req.onloadstart = opts.onloadstart || null;
        req.onloadend = opts.onloadend || null;
        req.ontimeout = opts.ontimeout || null;
        req.onprogress = function(e) {
            try {
                var a = new String(e.srcElement.response).split(opts.delimiter);
                for(var i=opts.index; i<a.length; i++) {
                    try {
                        var data = JSON.parse(a[i]); // may not be complete
                        if (typeof opts.onupdate==='function') opts.onupdate(data, i);
                        opts.index = i + 1;
                    } catch(fx){}
                }
            }
            catch(e){}
        };
        req.send(opts.data || null);
    };
})(jQuery);

ほとんどテストされていませんが、それはあなたが考えていたものを実行するようでした。私はそれがうまくいかないかもしれないあらゆる種類の方法を考えることができます;-)

$.longPull({ url: 'http://localhost:61873/Test', onupdate: function(data) { console.log(data); }});
3
Kris Oye

要求されたとおり、ここにいくつかの擬似NodeJSコードがあります:

function respond_to_client(res,session,cnt)
{
    //context: res is the object we use to respond to the client
    //session: just some info about the client, irrelevant here
    //cnt: initially 0

    //nothing to tell the client, let's long poll.
    if  (nothing_to_send(res,session)) 
    {
        if (cnt<MAX_LONG_POLL_TIME)
        {
            //call this function in 100 ms, increase the counter
            setTimeout(function(){respond_to_client(request_id,res,session,cnt+1)},100);
        }
        else
        {
            close_connection(res); 
            //Counter too high.
            //we have nothing to send and we kept the connection for too long,
            //close it. The client will open another.
        }
    }
    else 
    {
        send_what_we_have(res);
        close_connection(res);
        //the client will consume the data we sent, 
        //then quickly send another request.
    }

    return;

}
3
Hello World

通常のリクエストとの実際の違いはサーバー上で行われるため、そのコードだけではどのように機能するかはわかりません。

Javascriptは通常のリクエストを行うだけですが、サーバーはリクエストにすぐに応答する必要はありません。サーバーに返す価値のあるものが何もない場合(つまり、ブラウザーが待機している変更がまだ行われていない場合)、サーバーは接続を開いたままにするだけ待機します。

しばらくサーバーで何も起こらない場合、クライアント側がタイムアウトして新しいリクエストを行うか、サーバーはフローを続行するためだけに空の結果を返すことを選択できます。

2
Guffa

接続は常に開いたままではありません。サーバーから応答を受信したときに自動的に閉じられ、サーバーが接続を閉じます。長いポーリングでは、サーバーはすぐにデータを送り返すことは想定されていません。 ajaxではcomplete(サーバーが接続を閉じると)、新しい要求がサーバーに送信されます。サーバーは新しい接続を再び開き、新しい応答を待機し続けます。

前述のように、長いポーリングプロセスはクライアント側だけでなく、主にサーバー側でも処理されます。そして、サーバースクリプト(PHPの場合)だけでなく、タイムアウトによって "hanged"接続を閉じないサーバー自体によっても。

FWIW、 WebSockets サーバー側と常に開いている接続を使用します。これにより、接続を閉じずにデータを送受信できます。

1
VisioN

コードにtimeoutが必要な理由を適切に説明している人はいないでしょう。 jQuery Ajax docsから:

リクエストのタイムアウト(ミリ秒単位)を設定します。これにより、$。ajaxSetup()で設定されたグローバルタイムアウトが上書きされます。タイムアウト期間は、$。ajax呼び出しが行われた時点から始まります。他のいくつかの要求が進行中であり、ブラウザーに使用可能な接続がない場合、要求が送信される前にタイムアウトになる可能性があります

タイムアウトオプションは、実際に次の実行をX秒間遅らせません。現在の呼び出しの最大タイムアウトを設定するだけです。タイムアウトに関する良い記事- https://mashupweb.wordpress.com/2013/06/26/you-should-always-add-timeout-to-you-ajax-call-in-jquery/ =

1
Ilya Buziuk