Srautai
Phasis įgyvendina visą WHATWG Streams Standard. Kiekvieną klasę, kiekvieną skaitytuvo režimą ir kiekvieną pagalbinę funkciją. Tas pats kodas, kuris veikia Node ir šiuolaikinėse naršyklėse, veikia ir Phasis.
Tai įgyvendinimas, kurį fetch naudoja viduje — Response.body yra tikras ReadableStream, Request priima srautinius turinius, o tee(), reikalingas Response klonui sukurti, veikia.
Kas įtraukta
| Klasė | Būsena |
|---|---|
ReadableStream |
Pilna |
ReadableStreamDefaultController |
Pilna |
ReadableByteStreamController |
Pilna |
ReadableStreamDefaultReader |
Pilna |
ReadableStreamBYOBReader |
Pilna |
ReadableStreamBYOBRequest |
Pilna |
WritableStream |
Pilna |
WritableStreamDefaultController |
Pilna |
WritableStreamDefaultWriter |
Pilna |
TransformStream |
Pilna |
TransformStreamDefaultController |
Pilna |
ByteLengthQueuingStrategy |
Pilna |
CountQueuingStrategy |
Pilna |
Taip pat veikia dažniausiai naudojami metodai: pipeTo, pipeThrough, tee, getReader, asinchroninis iteravimas, Symbol.asyncIterator ir BYOB skaitymas naudojant { min }.
Duomenų pateikimas
// Pull-based — only generates values when read
const counter = new ReadableStream({
start(controller) { this.n = 0; },
pull(controller) {
if (this.n >= 5) { controller.close(); return; }
controller.enqueue(this.n++);
},
});
for await (const v of counter) console.log(v); // 0,1,2,3,4
// Push-based — start enqueues everything eagerly
const small = new ReadableStream({
start(c) {
[10, 20, 30].forEach(n => c.enqueue(n));
c.close();
},
});
Duomenų skaitymas
Trys skaitymo būdai:
// 1. Reader
const reader = stream.getReader();
while (true) {
const { value, done } = await reader.read();
if (done) break;
console.log(value);
}
reader.releaseLock();
// 2. Async iteration (preferred)
for await (const chunk of stream) {
console.log(chunk);
}
// 3. tee + parallel pipes
const [a, b] = stream.tee();
await Promise.all([a.pipeTo(sinkA), b.pipeTo(sinkB)]);
Transformavimas
const upper = new TransformStream({
transform(chunk, controller) {
controller.enqueue(chunk.toUpperCase());
},
});
const result = new ReadableStream({
start(c) { ['hi', 'there'].forEach(s => c.enqueue(s)); c.close(); }
}).pipeThrough(upper);
for await (const v of result) console.log(v); // HI, THERE
Baitų srautai (BYOB)
const bytes = new ReadableStream({
type: 'bytes',
start(controller) {
controller.enqueue(new Uint8Array([1, 2, 3, 4, 5, 6]));
controller.close();
},
});
const reader = bytes.getReader({ mode: 'byob' });
const buf = new Uint8Array(4);
const { value, done } = await reader.read(buf);
// value is a Uint8Array of length 4, sharing buffer with `buf`
{ min: N } palaikomas — read(view, { min: 2 }) išsprendžiamas tik tada, kai yra bent 2 elementai.
Atgalinis spaudimas
desiredSize ir ready veikia taip, kaip aprašyta specifikacijoje. Naudokite eilių strategiją, kad pateiktumėte duomenų gamintojui grįžtamąjį kanalą:
const stream = new ReadableStream({
pull(controller) {
if (controller.desiredSize <= 0) return; // back off
controller.enqueue(nextChunk());
},
}, new CountQueuingStrategy({ highWaterMark: 4 }));
Su fetch
// Response body is a ReadableStream
const res = await fetch('https://example.com/big.txt');
let total = 0;
for await (const chunk of res.body) {
total += chunk.byteLength;
}
// Request bodies can stream too
const upload = new ReadableStream({
start(c) { c.enqueue(new TextEncoder().encode('hello')); c.close(); }
});
await fetch('https://example.com/upload', { method: 'POST', body: upload });
Dvigubas srautas spartinimui
Dažnas šablonas: perskaityti turinį du kartus.
const res = await fetch(url);
const [forCache, forUse] = res.body.tee();
await Promise.all([
forCache.pipeTo(cacheWritable),
parseJson(forUse),
]);
Response.clone() tai atlieka už jus ir grąžina naują Response.
Apribojimai
- Tik sinchroniniai duomenų gamintojai.
pull(), atliekantis blokuojančias PHP įvesties ir išvesties operacijas, sustabdys scenarijų. HTTP naudokite Fetch transporto kablį; dirbant su failais, pirmiausia geriau įkelti juos į atmintį. PrieinamisetTimeout/setInterval(žr. Įvykių ciklas), tačiau pagal numatytąsias nuostatas variklis naudoja virtualųjį laiką —pull()viduje esantissetTimeout(cb, 1000)neiš tiesų PHP, o pasuka ciklo laikrodį pirmyn. Kad veiktų realaus laiko tempas, pagrindinė aplinka turi valdytitickEventLoop()pagal realų laikrodį.
Taip pat žr.
- Žiniatinklio API (WPT) — WPT sėkmės rodiklio lentelė, apimanti Streams papildomus testus.
- Fetch transportas — kaip užklausų ir atsakymų turiniai kerta PHP/JS ribą.
- AbortController šablonai — vykstančių skaitymo operacijų atšaukimas.