adopt()(Automatically releasing object URLs)
در مثال زیر، ما یک آدرس موقت (Object URL) برای یک شیء دادهایِ بلاب (Blob) میسازیم تا بتوانیم آن فایل را دانلود کنیم (در یک برنامه واقعی، این بلاب معمولاً از جایی مثل یک فایل سیستمی یا پاسخ یک درخواست fetch دریافت میشود).
برای جلوگیری از نشت منابع (Resource Leak)، باید حواسمان باشد که به محض اینکه دیگر به این آدرس نیاز نداریم (یعنی زمانی که فرآیند دانلود با موفقیت شروع شد)، آن را با متد URL.revokeObjectURL() از حافظه مرورگر پاک کنیم. از آنجا که خودِ آدرس URL صرفاً یک رشته متنی (String) است و پروتکل Disposable را پیادهسازی نکرده، نمیتوانیم مستقیماً متغیر url را با دستور using تعریف کنیم؛ بنابراین یک DisposableStack میسازیم تا نقش تصفیهکننده را برای این آدرس بازی کند. به محض اینکه اسکوپ این تصفیهکننده (Disposer) به پایان برسد (چه بعد از اجرای موفقیتآمیز کلیک روی لینک دانلود و چه در صورت بروز خطا در هر کجای مسیر)، این آدرس موقت خودکار از حافظه مرورگر پاک (Revoke) میشود:
const downloadButton = document.getElementById("download-button");
const exampleBlob = new Blob(["example data"]);
downloadButton.addEventListener("click", () => {
using disposer = new DisposableStack();
const link = document.createElement("a");
// ثبت آدرس موقت در پشته پاکسازی و معرفی متد تصفیه به آن
const url = disposer.adopt(
URL.createObjectURL(exampleBlob),
URL.revokeObjectURL,
);
link.href = url;
link.download = "example.txt";
link.click(); // شبیهسازی کلیک برای شروع دانلود
});
(Automatically cancelling in-progress requests)
در این مثال، ما میخواهیم لیستی از منابع شبکه را به صورت همزمان و موازی با استفاده از Promise.all() دریافت (Fetch) کنیم. رفتار Promise.all() به این صورت است که به محض خراب شدن و ریجکت شدنِ حتی یکی از درخواستها، کل پرامیس شکست میخورد؛ اما چالش اینجاست که بقیه درخواستهای معلق (Pending) همچنان در پسزمینه به کار خود ادامه میدهند، با اینکه نتایج آنها دیگر برای برنامه ما قابل دسترسی و استفاده نیست!
برای اینکه این درخواستهای باقیمانده بیهوده منابع شبکه و سیستم را مصرف نکنند، باید کاری کنیم که به محض به نتیجه رسیدن (یا شکست خوردن) فرآیندِ Promise.all()، درخواستهای در حال اجرا خودکار لغو (Cancel) شوند. ما این مکانیزم لغو را با ابزار AbortController پیادهسازی میکنیم و سیگنال آن (signal) را به تمام فراخوانیهای fetch() میفرستیم:
اگر Promise.all() با موفقیت کامل انجام شود، تابع به صورت عادی خروجی را برمیگرداند و کنترلر دستور abort() را صادر میکند؛ این کار هیچ ضرری ندارد چون دیگر درخواستِ معلقی وجود ندارد که بخواهد لغو شود.
اما اگر Promise.all() شکست بخورد و تابع خطا پرتاب کند، کنترلر فوراً دستور abort() را صادر کرده و تمام درخواستهای شبکه که هنوز در جریان هستند را در همان ثانیه لغو میکند.
async function getAllData(urls) {
using disposer = new DisposableStack();
// ثبت کنترلرِ لغو در پشته پاکسازی و معرفی متد تصفیه (abort) به آن
const { signal } = disposer.adopt(new AbortController(), (controller) =>
controller.abort(),
);
// دریافت تمام آدرسها به صورت موازی
// در صورت شکستِ هر کدام از درخواستها، بقیه مواردِ نیمهکاره خودکار لغو میشوند
const pages = await Promise.all(
urls.map((url) =>
fetch(url, { signal }).then((response) => {
if (!response.ok)
throw new Error(
`Response error: ${response.status} - ${response.statusText}`,
);
return response.text();
}),
),
);
return pages;
}
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://developer.mozilla.org/en-US/docs/Web/JavaScript