once / singleFlight

کاری را دقیقاً یک بار انجام می‌دهد و نتیجه را دوباره به کار می‌گیرد: راه‌اندازی تنبل برای تجزیهٔ پیکربندی، محاسبهٔ گران‌بهای یک‌باره، گیرنده‌های تنبل. once همگام است و singleFlight همتای ناهمگامش.

API

once(fn)

پارامتر توضیح نوع پیش‌فرض
fn تابعی که یک بار اجرا می‌شود؛ آنچه تابع نباشد همان‌طور برمی‌گردد Function | any الزامی

تابعی پیچیده‌شده برمی‌گرداند. نخستین فراخوانی ارزیابی و انباره می‌کند؛ هر فراخوانی بعدی همان نتیجهٔ نخست را می‌دهد، هر آرگومانی هم که بدهید.

singleFlight(fn)

پارامتر توضیح نوع پیش‌فرض
fn تابع ناهمگامی که یک بار اجرا می‌شود () => Promise<T> الزامی

تابعی پیچیده‌شده به‌همراه اینها برمی‌گرداند:

عضو توضیح نوع
reset() نتیجهٔ انباره‌شده را دور می‌ریزد تا فراخوانی بعدی دوباره fn را بدواند () => void
started اینکه نتیجه‌ای دارد یا همین حالا در حال اجراست boolean

memoize(fn)

نام دیگرِ منسوخِ once. هشدار پایین را ببینید.

نمونه

import { once, singleFlight } from 'ranuts';

// همگام: پیکربندی تنها در نخستین دسترسی تجزیه می‌شود
const config = once(() => JSON.parse(rawConfig));
config(); // تجزیه می‌کند
config(); // انباره‌شده را می‌دهد

// ناهمگام: پایگاه داده یک بار باز می‌شود، هر چند فراخواننده هم که رقابت کنند
const ready = singleFlight(() => db.openDataBase());
await Promise.all([ready(), ready(), ready()]); // یک بار باز می‌کند

یادداشت‌ها

  1. once بر پایهٔ آرگومان انباره نمی‌کند. تنها آرگومان‌های نخستین فراخوانی اثر دارند. اگر انبارهٔ به‌ازای هر آرگومان می‌خواهید، خودتان Map بگذارید.
  2. once پس از ارزیابی fn را رها می‌کند، پس هر چه آن تابع در چنگ داشت می‌تواند جمع‌آوری شود.
  3. singleFlight ردها را انباره نمی‌کند. تلاش ناکام، انباره را پاک می‌کند تا لغزش گذرای شبکه همچنان تکرارپذیر بماند. انباره کردن یک Promiseِ ردشده، یک تک‌لغزش را جاودانه می‌کرد.
  4. فراخوانندگان هم‌زمانِ singleFlight همان Promiseِ در جریان را شریک می‌شوند، پس fn حتی با رقابت N فراخواننده یک بار می‌دود. این همان پاسخ به آن اشکال کلاسیک است که «init() مقدار void می‌دهد، پس فراخواننده نمی‌تواند منتظرش بماند و نوشتن‌های زودهنگام شکست می‌خورند».