2

ノンブロッキングresponse.writeを書くことは可能ですか? ファイルのダウンロード中に他のクライアントが接続できるかどうかを確認する簡単なテストを作成しました。

var connect = require('connect');

var longString = 'a';
for (var i = 0; i < 29; i++) { // 512 MiB
   longString += longString;
}
console.log(longString.length)

function download(request, response) {
    response.setHeader("Content-Length", longString.length);
    response.setHeader("Content-Type", "application/force-download");
    response.setHeader("Content-Disposition", 'attachment; filename="file"');
    response.write(longString);
    response.end();
}

var app = connect().use(download);
connect.createServer(app).listen(80);

writeそして、ブロックしているようです!

私は何か間違ったことをしていますか?

更新なので、ブロックせず、同時にブロックします。2 つのファイルを同時にダウンロードできるという意味ではブロックしません。また、バッファの作成は長い操作であるという意味でブロックします。

4

2 に答える 2

2

JavaScript で厳密に行われた処理はすべてブロックされます。response.write()、少なくとも v0.8 の時点では、これも例外ではありません。

初めてresponse.write()呼び出されると、バッファリングされたヘッダー情報と最初の本文がクライアントに送信されます。2 回目のresponse.write()呼び出しでは、Node はデータをストリーミングすると想定し、それを個別に送信します。つまり、応答は本文の最初のチャンクまでバッファリングされます。

trueデータ全体がカーネル バッファに正常にフラッシュされたかどうかを返します。falseデータの全部または一部がユーザー メモリでキューに入れられたかどうかを返します。'drain'バッファが再び解放されたときに発行されます。

とにかく変換​​が発生するため、時間を節約できるのは、変換longStringBuffer試みる前にに変換することです。write()

var longString = 'a';
for (...) { ... }
longString = new Buffer(longString);

ただし、一度にすべてをストリーミングするよりも、さまざまなチャンクをストリーミングする方がおそらく良いでしょう(注:ストリームは v0.10 で変更されています)。longString

var longString = 'a',
    chunkCount = Math.pow(2, 29),
    bufferSize = Buffer.byteLength(longString),
    longBuffer = new Buffer(longString);

function download(request, response) {
    var current = 0;

    response.setHeader("Content-Length", bufferSize * chunkCount);
    response.setHeader("Content-Type", "application/force-download");
    response.setHeader("Content-Disposition", 'attachment; filename="file"');

    function writeChunk() {
        if (current < chunkCount) {
            current++;

            if (response.write(longBuffer)) {
                process.nextTick(writeChunk);
            } else {
                response.once('drain', writeChunk);
            }
        } else {
            response.end();
        }
    }

    writeChunk();
}

そして、最終的な目標がディスクからファイルをストリーミングすることである場合、これは and を使用するとさらに簡単にfs.createReadStream()なりstream.pipe()ます。

function download(request, response) {
    // response.setHeader(...)
    // ...

    fs.createReadStream('./file-on-disk').pipe(response);
}
于 2013-02-11T19:27:25.187 に答える
1

いいえ、ブロックしません。IE から 1 つを試し、Firefox からもう 1 つ試しました。最初にIEを実行しましたが、最初にFirefoxからファイルをダウンロードできました。1 MB (i < 20) で試してみましたが、同じように高速に動作します。作成する longString にはメモリ割り当てが必要であることを知っておく必要があります。i < 30 (Windows 7) で実行しようとすると、FATAL ERROR: JS Allocation failed - process out of memory がスローされます。

メモリの割り当て/コピーに時間がかかります。巨大なファイルであるため、応答に時間がかかり、ダウンロードがブロックされているように見えます。小さい値 (i < 20 または何か) については、自分で試してみてください。

于 2013-02-11T18:40:09.027 に答える