1. Analisis pembukaan
Stream adalah antarmuka abstrak yang diimplementasikan oleh banyak objek di Node. Misalnya, permintaan ke server HTTP adalah aliran, dan STDOUT juga merupakan aliran. Stream dapat dibaca, dapat ditulis atau keduanya.
Kontak pertama dengan Stream dimulai dengan UNIX awal. Latihan puluhan tahun telah membuktikan bahwa ide Stream dapat dengan mudah mengembangkan beberapa sistem besar.
Di UNIX, aliran diimplementasikan melalui "|". Dalam node, sebagai modul aliran bawaan, banyak modul inti dan modul tiga partai digunakan.
Seperti Unix, operasi utama aliran node adalah .pipe (), dan pengguna dapat menggunakan mekanisme penanggulangan untuk mengontrol keseimbangan antara baca dan tulis.
Stream dapat memberi pengembang antarmuka terpadu yang dapat menggunakan kembali dan mengontrol keseimbangan baca dan tulis antara aliran melalui antarmuka aliran abstrak.
Koneksi TCP adalah aliran yang dapat dibaca dan aliran yang dapat ditulis, sedangkan koneksi HTTP berbeda. Objek permintaan HTTP adalah aliran yang dapat dibaca, sedangkan objek respons HTTP adalah aliran yang dapat ditulis.
Proses transmisi aliran ditransmisikan dalam bentuk buffer secara default, kecuali Anda mengatur formulir penyandian lainnya untuk itu, berikut ini adalah contoh:
Salinan kode adalah sebagai berikut:
var http = membutuhkan ('http');
var server = http.createServer (function (req, res) {
res.writeHeader (200, {'tipe konten': 'teks/polos'});
res.end ("Halo, beruang besar!");
});
server.listen (8888);
Console.log ("Server HTTP berjalan di port 8888 ...");
Setelah berjalan, kode kacau akan muncul karena set karakter yang ditentukan tidak diatur, seperti: "UTF-8".
Cukup ubah:
Salinan kode adalah sebagai berikut:
var http = membutuhkan ('http');
var server = http.createServer (function (req, res) {
res.writeHeader (200, {
'Tipe konten': 'teks/polos; charset = utf-8' // tambahkan charset = utf-8
});
res.end ("Halo, beruang besar!");
});
server.listen (8888);
Console.log ("Server HTTP berjalan di port 8888 ...");
Hasil Menjalankan:
Mengapa menggunakan Stream
I/O di node tidak sinkron, jadi membaca dan menulis ke disk dan jaringan memerlukan membaca dan membaca data melalui fungsi callback. Berikut ini adalah contoh unduhan file
Pada kode:
Salinan kode adalah sebagai berikut:
var http = membutuhkan ('http');
var fs = membutuhkan ('fs');
var server = http.createServer (function (req, res) {
fs.readfile (__ dirname + '/data.txt', function (err, data) {
res.end (data);
});
});
server.listen (8888);
Kode dapat mengimplementasikan fungsi yang diperlukan, tetapi layanan perlu men -cache seluruh data file ke memori sebelum mengirim data file. Jika file "data.txt" sangat
Jika besar dan memiliki konkurensi yang besar, banyak memori akan terbuang sia -sia. Karena pengguna perlu menunggu sampai seluruh file di -cache ke memori untuk menerima data file, ini mengarah ke
Pengalaman pengguna cukup buruk. Untungnya, kedua parameter (req, res) adalah aliran, sehingga kita dapat menggunakan fs.createreadstream () bukan fs.readfile (). sebagai berikut:
Salinan kode adalah sebagai berikut:
var http = membutuhkan ('http');
var fs = membutuhkan ('fs');
var server = http.createServer (function (req, res) {
var stream = fs.createreadStream (__ dirname + '/data.txt');
stream.pipe (res);
});
server.listen (8888);
Metode .pipe () mendengarkan peristiwa 'data' dan 'akhir' dari fs.createreadstream (), sehingga file "data.txt" tidak perlu di -cache.
File dapat dikirim ke klien segera setelah koneksi klien selesai. Manfaat lain dari menggunakan .pipe () adalah bahwa itu dapat diselesaikan saat pelanggan
Baca dan tulis ketidakseimbangan yang disebabkan oleh penundaan akhir yang sangat besar.
Ada lima aliran dasar: dapat dibaca, dapat ditulisi, transformasi, dupleks, dan "klasik". (Harap periksa API untuk detailnya)
2. Perkenalkan contoh
Ketika data yang perlu diproses tidak dapat dimuat dalam memori pada satu waktu, atau ketika pemrosesan lebih efisien saat membaca, kita perlu menggunakan aliran data. NodeJS menyediakan operasi pada aliran data melalui berbagai aliran.
Mengambil program salinan file besar sebagai contoh, kami dapat membuat aliran data hanya baca untuk sumber data, contohnya adalah sebagai berikut:
Salinan kode adalah sebagai berikut:
var rs = fs.createreadstream (pathname);
rs.on ('data', function (chunk) {
dosomething (chunk); // Gunakan detail spesifik seperti yang Anda inginkan
});
rs.on ('end', function () {
pembersihan ();
});
Peristiwa data dalam kode akan dipicu terus menerus, terlepas dari apakah fungsi dosomething dapat diproses. Kode dapat dimodifikasi sebagai berikut untuk menyelesaikan masalah ini.
Salinan kode adalah sebagai berikut:
var rs = fs.createreadstream (src);
rs.on ('data', function (chunk) {
rs.pause ();
dosomething (chunk, function () {
rs.resume ();
});
});
rs.on ('end', function () {
pembersihan();
});
Panggilan balik ditambahkan ke fungsi dosomething, sehingga kami dapat menjeda pembacaan data sebelum memproses data dan terus membaca data setelah memproses data.
Selain itu, kami juga dapat membuat aliran data khusus untuk target data, sebagai berikut:
Salinan kode adalah sebagai berikut:
var rs = fs.createreadstream (src);
var ws = fs.createWriteStream (DST);
rs.on ('data', function (chunk) {
ws.write (chunk);
});
rs.on ('end', function () {
ws.end ();
});
Setelah dosomething digantikan dengan menulis data ke dalam aliran khusus, kode di atas terlihat seperti program salinan file. Namun, kode di atas memiliki masalah yang disebutkan di atas. Jika kecepatan tulis tidak dapat mengikuti kecepatan baca, hanya menulis cache di dalam aliran data yang akan meledak. Kita dapat menilai apakah data yang masuk telah ditulis ke target atau ditempatkan sementara di cache berdasarkan nilai pengembalian metode .write, dan menilai kapan hanya data tulis yang ditulis ke target berdasarkan peristiwa pembuangan, dan meneruskan data berikutnya yang akan ditulis. Oleh karena itu kodenya adalah sebagai berikut:
Salinan kode adalah sebagai berikut:
var rs = fs.createreadstream (src);
var ws = fs.createWriteStream (DST);
rs.on ('data', function (chunk) {
if (ws.write (chunk) === false) {
rs.pause ();
}
});
rs.on ('end', function () {
ws.end ();
});
ws.on ('drain', function () {
rs.resume ();
});
Akhirnya, transfer data dari aliran data hanya baca ke stream data khusus ditulis diwujudkan, dan kontrol gudang tahan ledakan disertakan. Karena ada banyak skenario penggunaan, seperti program salinan file besar di atas, NodeJS secara langsung menyediakan metode .pipe untuk melakukan ini, dan metode implementasinya yang mirip dengan kode di atas.
Berikut adalah proses penyalinan file yang lebih lengkap:
Salinan kode adalah sebagai berikut:
var fs = membutuhkan ('fs'),
path = membutuhkan ('path'),
out = Process.stdout;
var filepath = '/bb/bigbear.mkv';
var readStream = fs.createreadstream (filepath);
var writeStream = fs.createWriteStream ('file.mkv');
var stat = fs.statsync (filepath);
var totalSize = stat.size;
var passllength = 0;
var lastsize = 0;
var startTime = date.now ();
readStream.on ('data', function (chunk) {
lulus lulus += chunk.length;
if (writeStream.write (chunk) === false) {
readStream.Pause ();
}
});
readStream.on ('end', function () {
writeStream.end ();
});
writeStream.on ('drain', function () {
readStream.resume ();
});
setTimeout (function show () {
var persen = math.ceil ((lulus panjang / totalsize) * 100);
var size = math.ceil (passLength / 1000000);
var diff = ukuran - lastsize;
lastsize = ukuran;
out.clearline ();
out.cursorto (0);
out.write ('selesai' + ukuran + 'mb,' + persen + '%, kecepatan:' + diff * 2 + 'mb/s');
if (passlength <totalsize) {
setTimeout (show, 500);
} kalau tidak {
var endtime = date.now ();
console.log ();
Console.log ('When Shared:' + (EndTime - StartTime) / 1000 + 'detik.');
}
}, 500);
Anda dapat menyimpan kode di atas sebagai "copy.js". Eksperimen: Kami menambahkan pengaturan rekursif (atau secara langsung menggunakan setInterval) untuk menjadi pengamat.
Amati kemajuan penyelesaian setiap 500ms, dan tulis ukuran yang telah selesai, persentase dan salin kecepatan ke konsol bersama. Ketika menyalin selesai, total waktu dihitung.
Tiga, mari kita ringkas
(1) Memahami konsep aliran.
(2) Mahir dalam menggunakan API Stream yang relevan
(3) Perhatikan kontrol detail, seperti: Menyalin file besar, menggunakan bentuk "data chunk" untuk sharding.
(4), penggunaan pipa
(5), tekankan konsep lagi: koneksi TCP adalah aliran yang dapat dibaca dan aliran yang dapat ditulis, sedangkan koneksi HTTP berbeda. Objek permintaan HTTP adalah aliran yang dapat dibaca, sedangkan objek respons HTTP adalah aliran yang dapat ditulis.