Development Tip

jQuery는 AJAX 스트림을 점진적으로 읽습니까?

yourdevel 2020. 11. 4. 20:53
반응형

jQuery는 AJAX 스트림을 점진적으로 읽습니까?


이 질문 을 읽었 지만 내 질문에 정확히 대답하지 않습니다. 안타깝게도 AJAX를 마지막으로 살펴본 이후로 XHR 개체에서 변경된 것처럼 보이므로 responseText채우기가 완료되기 전에 더 이상 직접 액세스 할 수 없습니다 .

내가 제어 할 수없는 서버에서 HTTP를 통해 CSV 데이터를 검색하기 위해 AJAX (바람직하게는 jQuery,하지만 제안에 개방적 임)를 사용하는 페이지를 작성해야합니다. 응답 데이터는 상당히 클 수 있습니다. 메가 바이트의 텍스트는 드물지 않습니다.

서버는 스트림 친화적입니다. JavaScript에서 직접 반환되는 데이터 스트림에 액세스 할 수있는 방법이 있습니까?

중간에 있고 일종의 "Comet"기술 (long-polling, EventSource 등)을 사용하는 PHP 코드를 작성할 수있는 옵션이 있지만 가능하면 피하는 것이 좋습니다.

관련이있는 경우이 질문에 대해 사용자가 최신 버전의 Firefox / Chrome / Opera를 사용하고 있으며 이전 브라우저 호환성은 문제가되지 않는다고 가정합니다.


이를 위해 자바 스크립트를 바로 사용하고 싶을 것입니다. 그 이유는 콜백이 실행될 때까지 기다리지 않고 지속적으로 폴링하기를 원하기 때문입니다. 이를 위해 jQuery가 필요하지 않으며 매우 간단합니다. 그들은 몇 가지가 아약스 패턴 웹 사이트에서 이것에 대한 좋은 소스 코드를 .

기본적으로 응답에서 마지막 위치를 추적하고 해당 위치를지나 더 많은 텍스트를 주기적으로 폴링하기를 원할 것입니다. 귀하의 경우 차이점은 전체 이벤트를 구독하고 폴링을 중지 할 수 있다는 것입니다.


이것은 텍스트 나 HTML을 출력 할 때 매우 간단 합니다 . 아래는 예입니다.

( 그러나 JSON 을 출력하려고하면 문제가 발생합니다 . 이에 대해서는 더 자세히 설명하겠습니다.)

PHP 파일

header('Content-type: text/html; charset=utf-8');
function output($val)
{
    echo $val;
    flush();
    ob_flush();
    usleep(500000);
}
output('Begin... (counting to 10)');
for( $i = 0 ; $i < 10 ; $i++ )
{
    output($i+1);
}
output('End...');

HTML 파일

<!DOCTYPE>
<html>
    <head>
        <title>Flushed ajax test</title>
        <meta charset="UTF-8" />
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    </head>
    <body>
        <script type="text/javascript">
        var last_response_len = false;
        $.ajax('./flushed-ajax.php', {
            xhrFields: {
                onprogress: function(e)
                {
                    var this_response, response = e.currentTarget.response;
                    if(last_response_len === false)
                    {
                        this_response = response;
                        last_response_len = response.length;
                    }
                    else
                    {
                        this_response = response.substring(last_response_len);
                        last_response_len = response.length;
                    }
                    console.log(this_response);
                }
            }
        })
        .done(function(data)
        {
            console.log('Complete response = ' + data);
        })
        .fail(function(data)
        {
            console.log('Error: ', data);
        });
        console.log('Request Sent');
        </script>
    </body>
</html>

JSON으로이 작업을 수행해야하는 경우 어떻게합니까?

완전한 객체를 얻기 전까지는 구문이 항상 유효하지 않기 때문에 단일 JSON 객체를 점진적으로 (완전히로드되기 전에)로드하는 것은 실제로 불가능합니다.

그러나 응답에 여러 JSON 객체가 하나씩있는 경우 파이프 아래로 내려 오면서 한 번에 하나씩로드 할 수 있습니다.

그래서 위의 코드를 다음과 같이 수정했습니다.

  1. PHP FILE 라인 4를 echo $val;에서 echo '{"name":"'.$val.'"};'. 일련의 JSON 객체가 출력됩니다.

  2. HTML FILE 24 행을에서 console.log(this_response);변경

    this_response = JSON.parse(this_response);
    console.log(this_response.name);
    

    이 기초적인 코드는 브라우저로 들어오는 각 "청크"가 유효한 JSON 객체라고 가정합니다. 패킷이 어떻게 도착할지 예측할 수 없기 때문에 항상 그런 것은 아닙니다. 세미콜론을 기준으로 문자열을 분할해야 할 수도 있습니다 (또는 다른 구분 문자를 사용해야 할 수도 있습니다).

사용하지 마십시오 application/json

헤더를 다음과 같이 변경 하지 마십시오application/json . 3 일 동안 인터넷 검색이 가능했습니다. 응답 유형이 application/json이면 브라우저는 완전히 완료된 것처럼 응답이 완료 될 때까지 대기합니다. 그런 다음 전체 응답을 구문 분석하여 실제 JSON인지 확인합니다. 그러나 우리의 FULL 응답은 {...};{...};{...};유효한 JSON이 아닙니다. jqXHR.done메서드는 전체 응답을 JSON으로 구문 분석 할 수 없기 때문에 오류가 있다고 가정합니다.

주석에서 언급했듯이 다음을 사용하여 클라이언트 측에서이 검사를 비활성화 할 수 있습니다.

$.ajax(..., {dataType: "text"})

어떤 사람들이 이것이 유용하다고 생각하기를 바랍니다.


XMLHttpRequest.js 사용

https://github.com/ilinsky/xmlhttprequest

http://code.google.com/p/xmlhttprequest

  • XMLHttpRequest 1.0 객체의 눈에 잘 띄지 않는 표준 호환 (W3C) 브라우저 간 구현을 제공합니다.
  • 네이티브 XMLHttpRequest 객체 구현에서 관찰 된 모든 브라우저의 특성을 수정합니다.
  • XMLHttpRequest 객체 활동의 투명한 로깅을 활성화합니다.

PHP에서 긴 폴링을 사용하려면 :

output.php :

<?php
header('Content-type: application/octet-stream');

// Turn off output buffering
ini_set('output_buffering', 'off');
// Turn off PHP output compression
ini_set('zlib.output_compression', false);
// Implicitly flush the buffer(s)
ini_set('implicit_flush', true);
ob_implicit_flush(true);
// Clear, and turn off output buffering
while (ob_get_level() > 0) {
    // Get the curent level
    $level = ob_get_level();
    // End the buffering
    ob_end_clean();
    // If the current level has not changed, abort
    if (ob_get_level() == $level) break;
}
// Disable apache output buffering/compression
if (function_exists('apache_setenv')) {
    apache_setenv('no-gzip', '1');
    apache_setenv('dont-vary', '1');
}

// Count to 20, outputting each second
for ($i = 0;$i < 20; $i++) {
    echo $i.str_repeat(' ', 2048).PHP_EOL;
    flush();
    sleep(1);
}

run.php :

<script src="http://code.jquery.com/jquery-1.6.4.js"></script>
<script src="https://raw.github.com/ilinsky/xmlhttprequest/master/XMLHttpRequest.js"></script>

<script>
$(function() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', '/longpoll/', true);
    xhr.send(null);
    var timer;
    timer = window.setInterval(function() {
        if (xhr.readyState == XMLHttpRequest.DONE) {
            window.clearTimeout(timer);
            $('body').append('done <br />');
        }
        $('body').append('state: ' + xhr.readyState + '<br />');
        console.log(xhr.responseText);
        $('body').append('data: ' + xhr.responseText + '<br />');
    }, 1000);
});
</script>

다음과 같이 출력되어야합니다.

state: 3
data: 0
state: 3
data: 0 1
state: 3
data: 0 1 2
state: 3
data: 0 1 2 3
state: 3
data: 0 1 2 3 4
...
...
...
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
state: 3
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
done
state: 4
data: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 

IE의 경우 XDomainRequest를 살펴 봐야합니다.

http://blogs.msdn.com/b/ieinternals/archive/2010/04/06/comet-streaming-in-internet-explorer-with-xmlhttprequest-and-xdomainrequest.aspx

http://msdn.microsoft.com/en-us/library/cc288060(VS.85).aspx


서버가 스트림 친화적 (비동기)이라고 말하고 jquery 솔루션을 찾고 있었으므로 jQuery Stream Plugin을 확인 했습니까?

정말 사용하기 쉽고 아무것도 걱정할 필요가 없습니다. 그것은 또한 꽤 좋은 문서 를 가지고 있습니다.


Here is a straightforward way to achieve this using JQuery (as requested by the OP):

First, extend the ajax object to support onreadystatechange by running the below code from https://gist.github.com/chrishow/3023092 (appended at the bottom of this response). Then just call ajax using an onreadystatechange function that will check xhr.responseText for new text.

If you wanted to get even fancier, you could clear the responseText data each time you read it, such as described here).

For example, see https://jsfiddle.net/g1jmwcmw/1/, which will download the response from https://code.jquery.com/jquery-1.5.js and output it in chunks inside your console window, using the code below (which you can just copy into an html page and then open in your browser):

<!-- jquery >= 1.5. maybe earlier too but not sure -->
<script src=https://code.jquery.com/jquery-1.5.min.js></script>
<script>
/* One-time setup (run once before other code)
 *   adds onreadystatechange to $.ajax options
 *   from https://gist.github.com/chrishow/3023092)
 *   success etc will still fire if provided
 */
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
    if ( options.onreadystatechange ) {
        var xhrFactory = options.xhr;
        options.xhr = function() {
            var xhr = xhrFactory.apply( this, arguments );
            function handler() {
                options.onreadystatechange( xhr, jqXHR );
            }
            if ( xhr.addEventListener ) {
                xhr.addEventListener( "readystatechange", handler, false );
            } else {
                setTimeout( function() {
                    var internal = xhr.onreadystatechange;
                    if ( internal ) {
                        xhr.onreadystatechange = function() {
                            handler();
                            internal.apply( this, arguments ); 
                        };
                    }
                }, 0 );
            }
            return xhr;
        };
    }
});

// ----- myReadyStateChange(): this will do my incremental processing -----
var last_start = 0; // using global var for over-simplified example
function myReadyStateChange(xhr /*, jqxhr */) {
    if(xhr.readyState >= 3 && xhr.responseText.length > last_start) {
        var chunk = xhr.responseText.slice(last_start);
        alert('Got chunk: ' + chunk);
        console.log('Got chunk: ', chunk);
        last_start += chunk.length;
    }
}

// ----- call my url and process response incrementally -----
last_start = 0;
$.ajax({
  url: "https://code.jquery.com/jquery-1.5.js", // whatever your target url is goes here
  onreadystatechange: myReadyStateChange
});

</script>

참고URL : https://stackoverflow.com/questions/7740646/jquery-read-ajax-stream-incrementally

반응형