التدفقات
ينفذ Phasis معيار تدفقات WHATWG كاملًا. كل فئة وكل نمط قارئ وكل مساعد. تعمل الشيفرة نفسها التي تعمل في Node والمتصفحات الحديثة في Phasis.
التنفيذ هو ما يستخدمه fetch داخليًا — فـResponse.body هو ReadableStream حقيقي، ويقبل Request أجسام الاستجابة المتدفقة، وتعمل tee() اللازمة لاستنساخ Response.
ما تم شحنه
| الفئة | الحالة |
|---|---|
ReadableStream |
كاملة |
ReadableStreamDefaultController |
كاملة |
ReadableByteStreamController |
كاملة |
ReadableStreamDefaultReader |
كاملة |
ReadableStreamBYOBReader |
كاملة |
ReadableStreamBYOBRequest |
كاملة |
WritableStream |
كاملة |
WritableStreamDefaultController |
كاملة |
WritableStreamDefaultWriter |
كاملة |
TransformStream |
كاملة |
TransformStreamDefaultController |
كاملة |
ByteLengthQueuingStrategy |
كاملة |
CountQueuingStrategy |
كاملة |
إضافةً إلى الأساليب التي تحتاج إليها: pipeTo، pipeThrough، tee، getReader، والتكرار غير المتزامن، وSymbol.asyncIterator، وقراءة BYOB باستخدام { min }.
الإنتاج
JavaScript
// 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
JavaScript
// Push-based — start enqueues everything eagerly
const small = new ReadableStream({
start(c) {
[10, 20, 30].forEach(n => c.enqueue(n));
c.close();
},
});
الاستهلاك
ثلاث طرق للقراءة:
JavaScript
// 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)]);
التحويل
JavaScript
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
تدفقات البايتات (BYOB)
JavaScript
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 } مدعوم — لا يُحلّ read(view, { min: 2 }) إلا عند توفر عنصرين على الأقل.
الضغط العكسي
يعمل desiredSize وready كما يصف المعيار. استخدم استراتيجية اصطفاف لمنح المنتج قناةً عكسية:
JavaScript
const stream = new ReadableStream({
pull(controller) {
if (controller.desiredSize <= 0) return; // back off
controller.enqueue(nextChunk());
},
}, new CountQueuingStrategy({ highWaterMark: 4 }));
مع fetch
JavaScript
// 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 });
Tee للتخزين المؤقت
نمط شائع: قراءة المتن مرتين.
JavaScript
const res = await fetch(url);
const [forCache, forUse] = res.body.tee();
await Promise.all([
forCache.pipeTo(cacheWritable),
parseJson(forUse),
]);
يتولى Response.clone() ذلك ويعيد Response جديدًا.
ملاحظات
- المنتِجات المتزامنة فقط. سيؤدي
pull()الذي ينفذ عمليات إدخال وإخراج حاجبة عبر PHP إلى حجب البرنامج النصي. استخدم خطاف نقل fetch من أجل HTTP؛ وبالنسبة إلى الملفات، يُفضّل قراءتها كاملةً إلى الذاكرة مسبقًا. يتوفرsetTimeout/setInterval(انظر حلقة الأحداث)، لكن المحرك يستخدم وقتًا افتراضيًا افتراضيًا — فـsetTimeout(cb, 1000)داخلpull()لا ينتظر PHP، بل يقدّم ساعة الحلقة. يتطلب ضبط الإيقاع في الوقت الفعلي أن يقود المضيفtickEventLoop()وفق ساعة فعلية.
راجع أيضًا
- واجهات Web API (WPT) — جدول معدل اجتياز WPT الذي يغطي الاختبارات الفرعية للتدفقات.
- نقل Fetch — كيفية عبور متني الطلب والاستجابة للحد الفاصل بين PHP وJS.
- أنماط AbortController — إلغاء عمليات القراءة الجارية.