jQueryの$.ajaxで通信途中のresponseTextを取得する

Chunked transfer encoding で通信しようとすると readyState が4じゃなくても結果を取得しなければなりません。
ところが、jQuery (1.7.1) の $.ajax の返すオブジェクトは、コメントに Fake xhr とあるように XMLHttpRequest ではないため、readyState が4になるまで XMLHttpRequest.responseText を取得することができません。1

jQuery のソースを眺めていて、これならできそうだなぁと思って書いてみたらFirefox 8で問題なく動作したので載せておきます。

<html>
<head>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.js"></script>
<script type="text/javascript">
$(function() {
    console.log('start');
    $.ajax({
        type: 'post',
        url: './push.php',
        xhrFields: {
            onloadstart: function() {
                var xhr = this;
                $.mytimer = setInterval(function() {
                    console.log(xhr.responseText);
                }, 1000);
            }
        },
        success: function() {
            console.log('finished!');
            // すぐにクリアしてしまうと最終的なレスポンスに対する処理ができないので
            // タイマーと同じ間隔を空けてクリアする必要がある
            //clearInterval($.mytimer);
            setTimeout('clearInterval($.mytimer)', 1000);
        }
    });
});
</script>
</head>

ポイントは xhrFields に onloadstart を指定しているところです。xhrFields が定義されている場合、

// Apply custom fields if provided
if ( s.xhrFields ) {
    for ( i in s.xhrFields ) {
        xhr[ i ] = s.xhrFields[ i ];  // xhr は XMLHttpRequest オブジェクト
    }
}

という形で XMLHttpRequest オブジェクトにフィールドを追加することができます。
ちなみに xhrFields は1.5.1から追加された項目みたいです cf. http://api.jquery.com/jQuery.ajax/

サーバ側のコードはこちらのものを拝借します。
push.php

<?php
// push.php

function output_chunk($chunk)
{
    echo sprintf("%x\r\n", strlen($chunk));
    echo $chunk . "\r\n";
}

header("Content-type: application/octet-stream");
header("Transfer-encoding: chunked");
flush();

for ($i = 0; $i < 10; $i++) {
    output_chunk(
        json_encode(array("response" => "hoge", "count" => $i)) .
        str_repeat(' ', 8000) .
        "\n"
    );
    flush();
    sleep(1);
}
echo "0\r\n\r\n";

HTMLファイルにアクセスすると、Firebugには次のように表示されます。ちゃんと途中の値も表示されていますね!
20111225040827

これで jQuery でも柔軟な処理が行えますね!!

  1. XMLHttpRequest に DOMContentLoaded イベントを追加し、このイベントに対するコールバック関数が呼ばれた時に XMLHttpRequest.responseText を取得するみたいです 

広告
RでMySQL風に出力する Favmemoリニューアルしました!!
※このエントリーははてなダイアリーから移行したものです。過去のコメントなどはそちらを参照してください