از () scheduler.yield برای جدا کردن وظایف طولانی استفاده کنید

تاریخ انتشار: 6 مارس 2025

Browser Support

  • کروم: 129.
  • لبه: 129.
  • فایرفاکس: پشتیبانی نمی شود.
  • سافاری: پشتیبانی نمی شود.

Source

زمانی که کارهای طولانی موضوع اصلی را مشغول نگه می‌دارند، صفحه کند و بی پاسخ می‌شود و از انجام کارهای مهم دیگر مانند پاسخ دادن به ورودی کاربر جلوگیری می‌کند. در نتیجه، حتی کنترل‌های فرم داخلی ممکن است برای کاربران شکسته به نظر برسند - گویی صفحه ثابت شده است - به اجزای سفارشی پیچیده‌تر اهمیتی نمی‌دهید.

scheduler.yield() راهی برای تسلیم شدن به رشته اصلی است – به مرورگر اجازه می‌دهد هر کار با اولویت بالا را اجرا کند – سپس اجرا را از جایی که متوقف شده ادامه می‌دهد. این یک صفحه را پاسخگوتر نگه می دارد و به نوبه خود به بهبود تعامل با رنگ بعدی (INP) کمک می کند.

scheduler.yield یک API ارگونومیک ارائه می دهد که دقیقاً همان کاری را که می گوید انجام می دهد: اجرای تابعی که فراخوانی می شود در عبارت await scheduler.yield() مکث می کند و به رشته اصلی تسلیم می شود و وظیفه را از بین می برد. اجرای بقیه تابع - که ادامه تابع نامیده می شود - در یک کار حلقه رویداد جدید برنامه ریزی می شود.

async function respondToUserClick() {
  giveImmediateFeedback();
  await scheduler.yield(); // Yield to the main thread.
  slowerComputation();
}

مزیت خاص scheduler.yield این است که ادامه پس از بازده برنامه ریزی شده قبل از اجرای هر کار مشابه دیگری که توسط صفحه در صف قرار گرفته است اجرا شود. ادامه یک کار را بر شروع کارهای جدید اولویت می دهد.

توابعی مانند setTimeout یا scheduler.postTask نیز می‌توانند برای جدا کردن وظایف مورد استفاده قرار گیرند، اما این ادامه‌ها معمولاً پس از هر کار جدید از قبل در صف اجرا می‌شوند و به طور بالقوه خطر تأخیرهای طولانی بین تسلیم شدن به رشته اصلی و تکمیل کار آنها را به همراه دارد.

تداوم بعد از تسلیم اولویت بندی شده است

scheduler.yield بخشی از API زمان‌بندی وظایف اولویت‌دار است. به عنوان توسعه‌دهندگان وب، ما معمولاً در مورد ترتیبی که حلقه رویداد وظایف را بر اساس اولویت‌های صریح اجرا می‌کند، صحبت نمی‌کنیم، اما اولویت‌های نسبی همیشه وجود دارند ، مانند یک درخواست پاسخ به تماس requestIdleCallback که پس از هر پاسخ‌دهی setTimeout در صف اجرا می‌شود، یا یک شنونده رویداد ورودی راه‌اندازی شده که معمولاً قبل از یک کار در صف قرار می‌گیرد، اجرا می‌شود setTimeout(callback, 0) .

زمان‌بندی وظایف اولویت‌دار فقط این موضوع را واضح‌تر می‌کند، و تشخیص اینکه کدام کار قبل از دیگری اجرا می‌شود را آسان‌تر می‌کند و امکان تنظیم اولویت‌ها برای تغییر ترتیب اجرا، در صورت نیاز را فراهم می‌کند.

همانطور که گفته شد، ادامه اجرای یک تابع پس از تسلیم شدن با scheduler.yield() اولویت بیشتری نسبت به شروع کارهای دیگر دارد. مفهوم راهنما این است که ادامه یک کار باید ابتدا اجرا شود، قبل از اینکه به کارهای دیگر بروید. اگر کار کدی است که به خوبی رفتار می‌کند و به‌طور دوره‌ای نمایش داده می‌شود تا مرورگر بتواند کارهای مهم دیگری را انجام دهد (مانند پاسخ به ورودی کاربر)، نباید با اولویت‌بندی پس از سایر کارهای مشابه مجازات شود.

در اینجا یک مثال آورده شده است: دو تابع، در صف برای اجرا در وظایف مختلف با استفاده از setTimeout .

setTimeout(myJob);
setTimeout(someoneElsesJob);

در این مورد، دو فراخوان setTimeout دقیقاً در کنار یکدیگر قرار دارند، اما در یک صفحه واقعی، می‌توانند در مکان‌های کاملاً متفاوتی فراخوانی شوند، مانند یک اسکریپت شخص اول و یک اسکریپت شخص ثالث که به طور مستقل کار را برای اجرا تنظیم می‌کند، یا می‌تواند دو کار از مؤلفه‌های جداگانه باشد که در عمق زمان‌بندی فریمورک شما فعال می‌شوند.

این کار در DevTools چگونه می تواند باشد:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

myJob به عنوان یک کار طولانی علامت گذاری شده است و مرورگر را از انجام هر کار دیگری در حین اجرا مسدود می کند. با فرض اینکه از یک اسکریپت شخص اول است، می توانیم آن را تجزیه کنیم:

function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with setTimeout() to break up long task, then run part2.
  setTimeout(myJobPart2, 0);
}

از آنجایی که myJobPart2 قرار بود با setTimeout در myJob اجرا شود، اما این زمان‌بندی پس از اینکه someoneElsesJob قبلاً برنامه‌ریزی شده بود اجرا می‌شود، نحوه اجرا به این صورت است:

سه کار در پانل عملکرد Chrome DevTools نشان داده شده است. اولی تابع 'myJobPart1' را اجرا می کند، دومی یک کار طولانی است که 'someoneElsesJob' را اجرا می کند، و در نهایت وظیفه سوم اجرای 'myJobPart2' است.

ما کار را با setTimeout تقسیم کرده‌ایم تا مرورگر بتواند در اواسط myJob پاسخگو باشد، اما اکنون بخش دوم myJob فقط پس از پایان کار someoneElsesJob اجرا می‌شود.

در برخی موارد، ممکن است خوب باشد، اما معمولاً این بهینه نیست. myJob در حال تسلیم شدن به موضوع اصلی بود تا مطمئن شود که صفحه می‌تواند به ورودی کاربر پاسخگو باشد، نه اینکه موضوع اصلی را به طور کامل رها کند. در مواردی که someoneElsesJob به خصوص کند است، یا بسیاری از کارهای دیگر غیر از someoneElsesJob نیز برنامه ریزی شده اند، ممکن است زمان زیادی طول بکشد تا نیمه دوم myJob اجرا شود. احتمالاً این هدف توسعه‌دهنده نبود که setTimeout را به myJob اضافه کرد.

scheduler.yield() را وارد کنید، که ادامه هر تابعی را که آن را فراخوانی می کند در یک صف اولویت کمی بالاتر از شروع هر کار مشابه دیگری قرار می دهد. اگر myJob برای استفاده از آن تغییر کند:

async function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with scheduler.yield() to break up long task, then run part2.
  await scheduler.yield();
  myJobPart2();
}

حالا اجرا به صورت زیر است:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

مرورگر هنوز این فرصت را دارد که پاسخگو باشد، اما اکنون ادامه کار myJob بر شروع کار جدید someoneElsesJob اولویت دارد، بنابراین myJob قبل از شروع someoneElsesJob کامل می شود. این به انتظار تسلیم شدن به نخ اصلی برای حفظ پاسخگویی بسیار نزدیکتر است، نه اینکه موضوع اصلی را به طور کامل رها کنید.

وراثت اولویت دار

به‌عنوان بخشی از API برنامه‌ریزی وظایف اولویت‌دار بزرگ‌تر، scheduler.yield() به خوبی با اولویت‌های صریح موجود در scheduler.postTask() ترکیب می‌شود. بدون تعیین اولویت مشخص، یک scheduler.yield() در یک callback scheduler.postTask() اساساً مانند مثال قبلی عمل می کند.

با این حال، اگر اولویتی تنظیم شده باشد، مانند استفاده از اولویت 'background' کم:

async function lowPriorityJob() {
  part1();
  await scheduler.yield();
  part2();
}

scheduler.postTask(lowPriorityJob, {priority: 'background'});

ادامه با اولویتی بالاتر از سایر وظایف 'background' برنامه‌ریزی می‌شود – دریافت ادامه اولویت‌بندی شده مورد انتظار قبل از هر کار 'background' معلق – اما همچنان اولویت کمتری نسبت به سایر وظایف پیش‌فرض یا با اولویت بالا است. کار 'background' باقی می ماند.

این به این معنی است که اگر کار با اولویت پایین را با یک 'background' scheduler.postTask() (یا با requestIdleCallback ) برنامه ریزی کنید، ادامه بعد از scheduler.yield() درون نیز منتظر می ماند تا اکثر وظایف دیگر کامل شوند و رشته اصلی برای اجرا بیکار باشد، که دقیقاً همان چیزی است که شما از بازدهی در یک کار با اولویت پایین می خواهید.

نحوه استفاده از API

در حال حاضر، scheduler.yield() فقط در مرورگرهای مبتنی بر Chromium در دسترس است، بنابراین برای استفاده از آن باید ویژگی‌های شناسایی و بازگشت به روش ثانویه بازدهی برای مرورگرهای دیگر را داشته باشید.

scheduler-polyfill یک polyfill کوچک برای scheduler.postTask و scheduler.yield است که به صورت داخلی از ترکیبی از روش‌ها برای شبیه‌سازی مقدار زیادی از قدرت APIهای زمان‌بندی در مرورگرهای دیگر استفاده می‌کند (اگرچه وراثت اولویت scheduler.yield() پشتیبانی نمی‌شود).

برای کسانی که به دنبال اجتناب از polyfill هستند، یک روش این است که با استفاده از setTimeout() تسلیم شوند و از دست دادن یک ادامه اولویت‌دار را بپذیرند، یا حتی در مرورگرهای پشتیبانی‌نشده در صورتی که قابل قبول نیست، تسلیم نشوند. برای اطلاعات بیشتر، مستندات scheduler.yield() را در بهینه سازی وظایف طولانی ببینید.

اگر می‌خواهید ویژگی scheduler.yield() را شناسایی کنید و خودتان یک نسخه جایگزین اضافه کنید، می‌توانید از انواع wicg-task-scheduling برای بررسی نوع و پشتیبانی IDE نیز استفاده کنید.

بیشتر بدانید

برای کسب اطلاعات بیشتر در مورد API و نحوه تعامل آن با اولویت‌های کار و scheduler.postTask() ، اسناد scheduler.yield() و اولویت‌بندی کارها را در MDN بررسی کنید.

برای کسب اطلاعات بیشتر در مورد وظایف طولانی، نحوه تأثیر آنها بر تجربه کاربر و کارهایی که باید در مورد آنها انجام دهید، درباره بهینه سازی کارهای طولانی بخوانید.

،

تاریخ انتشار: 6 مارس 2025

Browser Support

  • کروم: 129.
  • لبه: 129.
  • فایرفاکس: پشتیبانی نمی شود.
  • سافاری: پشتیبانی نمی شود.

Source

زمانی که کارهای طولانی موضوع اصلی را مشغول نگه می‌دارند، صفحه کند و بی پاسخ می‌شود و از انجام کارهای مهم دیگر مانند پاسخ دادن به ورودی کاربر جلوگیری می‌کند. در نتیجه، حتی کنترل‌های فرم داخلی ممکن است برای کاربران شکسته به نظر برسند - گویی صفحه ثابت شده است - به اجزای سفارشی پیچیده‌تر اهمیتی نمی‌دهید.

scheduler.yield() راهی برای تسلیم شدن به رشته اصلی است – به مرورگر اجازه می‌دهد هر کار با اولویت بالا را اجرا کند – سپس اجرا را از جایی که متوقف شده ادامه می‌دهد. این یک صفحه را پاسخگوتر نگه می دارد و به نوبه خود به بهبود تعامل با رنگ بعدی (INP) کمک می کند.

scheduler.yield یک API ارگونومیک ارائه می دهد که دقیقاً همان کاری را که می گوید انجام می دهد: اجرای تابعی که فراخوانی می شود در عبارت await scheduler.yield() مکث می کند و به رشته اصلی تسلیم می شود و وظیفه را از بین می برد. اجرای بقیه تابع - که ادامه تابع نامیده می شود - در یک کار حلقه رویداد جدید برنامه ریزی می شود.

async function respondToUserClick() {
  giveImmediateFeedback();
  await scheduler.yield(); // Yield to the main thread.
  slowerComputation();
}

مزیت خاص scheduler.yield این است که ادامه پس از بازده برنامه ریزی شده قبل از اجرای هر کار مشابه دیگری که توسط صفحه در صف قرار گرفته است اجرا شود. ادامه یک کار را بر شروع کارهای جدید اولویت می دهد.

توابعی مانند setTimeout یا scheduler.postTask نیز می‌توانند برای جدا کردن وظایف مورد استفاده قرار گیرند، اما این ادامه‌ها معمولاً پس از هر کار جدید از قبل در صف اجرا می‌شوند و به طور بالقوه خطر تأخیرهای طولانی بین تسلیم شدن به رشته اصلی و تکمیل کار آنها را به همراه دارد.

تداوم بعد از تسلیم اولویت بندی شده است

scheduler.yield بخشی از API زمان‌بندی وظایف اولویت‌دار است. به عنوان توسعه‌دهندگان وب، ما معمولاً در مورد ترتیبی که حلقه رویداد وظایف را بر اساس اولویت‌های صریح اجرا می‌کند، صحبت نمی‌کنیم، اما اولویت‌های نسبی همیشه وجود دارند ، مانند یک درخواست پاسخ به تماس requestIdleCallback که پس از هر پاسخ‌دهی setTimeout در صف اجرا می‌شود، یا یک شنونده رویداد ورودی راه‌اندازی شده که معمولاً قبل از یک کار در صف قرار می‌گیرد، اجرا می‌شود setTimeout(callback, 0) .

زمان‌بندی وظایف اولویت‌دار فقط این موضوع را واضح‌تر می‌کند، و تشخیص اینکه کدام کار قبل از دیگری اجرا می‌شود را آسان‌تر می‌کند و امکان تنظیم اولویت‌ها برای تغییر ترتیب اجرا، در صورت نیاز را فراهم می‌کند.

همانطور که گفته شد، ادامه اجرای یک تابع پس از تسلیم شدن با scheduler.yield() اولویت بیشتری نسبت به شروع کارهای دیگر دارد. مفهوم راهنما این است که ادامه یک کار باید ابتدا اجرا شود، قبل از اینکه به کارهای دیگر بروید. اگر کار کدی است که به خوبی رفتار می‌کند و به‌طور دوره‌ای نمایش داده می‌شود تا مرورگر بتواند کارهای مهم دیگری را انجام دهد (مانند پاسخ به ورودی کاربر)، نباید با اولویت‌بندی پس از سایر کارهای مشابه مجازات شود.

در اینجا یک مثال آورده شده است: دو تابع، در صف برای اجرا در وظایف مختلف با استفاده از setTimeout .

setTimeout(myJob);
setTimeout(someoneElsesJob);

در این مورد، دو فراخوان setTimeout دقیقاً در کنار یکدیگر قرار دارند، اما در یک صفحه واقعی، می‌توانند در مکان‌های کاملاً متفاوتی فراخوانی شوند، مانند یک اسکریپت شخص اول و یک اسکریپت شخص ثالث که به طور مستقل کار را برای اجرا تنظیم می‌کند، یا می‌تواند دو کار از مؤلفه‌های جداگانه باشد که در عمق زمان‌بندی فریمورک شما فعال می‌شوند.

این کار در DevTools چگونه می تواند باشد:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

myJob به عنوان یک کار طولانی علامت گذاری شده است و مرورگر را از انجام هر کار دیگری در حین اجرا مسدود می کند. با فرض اینکه از یک اسکریپت شخص اول است، می توانیم آن را تجزیه کنیم:

function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with setTimeout() to break up long task, then run part2.
  setTimeout(myJobPart2, 0);
}

از آنجایی که myJobPart2 قرار بود با setTimeout در myJob اجرا شود، اما این زمان‌بندی پس از اینکه someoneElsesJob قبلاً برنامه‌ریزی شده بود اجرا می‌شود، نحوه اجرا به این صورت است:

سه کار در پانل عملکرد Chrome DevTools نشان داده شده است. اولی تابع 'myJobPart1' را اجرا می کند، دومی یک کار طولانی است که 'someoneElsesJob' را اجرا می کند، و در نهایت وظیفه سوم اجرای 'myJobPart2' است.

ما کار را با setTimeout تقسیم کرده‌ایم تا مرورگر بتواند در اواسط myJob پاسخگو باشد، اما اکنون بخش دوم myJob فقط پس از پایان کار someoneElsesJob اجرا می‌شود.

در برخی موارد، ممکن است خوب باشد، اما معمولاً این بهینه نیست. myJob در حال تسلیم شدن به موضوع اصلی بود تا مطمئن شود که صفحه می‌تواند به ورودی کاربر پاسخگو باشد، نه اینکه موضوع اصلی را به طور کامل رها کند. در مواردی که someoneElsesJob به خصوص کند است، یا بسیاری از کارهای دیگر غیر از someoneElsesJob نیز برنامه ریزی شده اند، ممکن است زمان زیادی طول بکشد تا نیمه دوم myJob اجرا شود. احتمالاً این هدف توسعه‌دهنده نبود که setTimeout را به myJob اضافه کرد.

scheduler.yield() را وارد کنید، که ادامه هر تابعی را که آن را فراخوانی می کند در یک صف اولویت کمی بالاتر از شروع هر کار مشابه دیگری قرار می دهد. اگر myJob برای استفاده از آن تغییر کند:

async function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with scheduler.yield() to break up long task, then run part2.
  await scheduler.yield();
  myJobPart2();
}

حالا اجرا به صورت زیر است:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

مرورگر هنوز این فرصت را دارد که پاسخگو باشد، اما اکنون ادامه کار myJob بر شروع کار جدید someoneElsesJob اولویت دارد، بنابراین myJob قبل از شروع someoneElsesJob کامل می شود. این به انتظار تسلیم شدن به نخ اصلی برای حفظ پاسخگویی بسیار نزدیکتر است، نه اینکه موضوع اصلی را به طور کامل رها کنید.

وراثت اولویت دار

به‌عنوان بخشی از API برنامه‌ریزی وظایف اولویت‌دار بزرگ‌تر، scheduler.yield() به خوبی با اولویت‌های صریح موجود در scheduler.postTask() ترکیب می‌شود. بدون تعیین اولویت مشخص، یک scheduler.yield() در یک callback scheduler.postTask() اساساً مانند مثال قبلی عمل می کند.

با این حال، اگر اولویتی تنظیم شده باشد، مانند استفاده از اولویت 'background' کم:

async function lowPriorityJob() {
  part1();
  await scheduler.yield();
  part2();
}

scheduler.postTask(lowPriorityJob, {priority: 'background'});

ادامه با اولویتی بالاتر از سایر وظایف 'background' برنامه‌ریزی می‌شود – دریافت ادامه اولویت‌بندی شده مورد انتظار قبل از هر کار 'background' معلق – اما همچنان اولویت کمتری نسبت به سایر وظایف پیش‌فرض یا با اولویت بالا است. کار 'background' باقی می ماند.

این به این معنی است که اگر کار با اولویت پایین را با یک 'background' scheduler.postTask() (یا با requestIdleCallback ) برنامه ریزی کنید، ادامه بعد از scheduler.yield() درون نیز منتظر می ماند تا اکثر وظایف دیگر کامل شوند و رشته اصلی برای اجرا بیکار باشد، که دقیقاً همان چیزی است که شما از بازدهی در یک کار با اولویت پایین می خواهید.

نحوه استفاده از API

در حال حاضر، scheduler.yield() فقط در مرورگرهای مبتنی بر Chromium در دسترس است، بنابراین برای استفاده از آن باید ویژگی‌های شناسایی و بازگشت به روش ثانویه بازدهی برای مرورگرهای دیگر را داشته باشید.

scheduler-polyfill یک polyfill کوچک برای scheduler.postTask و scheduler.yield است که به صورت داخلی از ترکیبی از روش‌ها برای شبیه‌سازی مقدار زیادی از قدرت APIهای زمان‌بندی در مرورگرهای دیگر استفاده می‌کند (اگرچه وراثت اولویت scheduler.yield() پشتیبانی نمی‌شود).

برای کسانی که به دنبال اجتناب از polyfill هستند، یک روش این است که با استفاده از setTimeout() تسلیم شوند و از دست دادن یک ادامه اولویت‌دار را بپذیرند، یا حتی در مرورگرهای پشتیبانی‌نشده در صورتی که قابل قبول نیست، تسلیم نشوند. برای اطلاعات بیشتر، مستندات scheduler.yield() را در بهینه سازی وظایف طولانی ببینید.

اگر می‌خواهید ویژگی scheduler.yield() را شناسایی کنید و خودتان یک نسخه جایگزین اضافه کنید، می‌توانید از انواع wicg-task-scheduling برای بررسی نوع و پشتیبانی IDE نیز استفاده کنید.

بیشتر بدانید

برای کسب اطلاعات بیشتر در مورد API و نحوه تعامل آن با اولویت‌های کار و scheduler.postTask() ، اسناد scheduler.yield() و اولویت‌بندی کارها را در MDN بررسی کنید.

برای کسب اطلاعات بیشتر در مورد وظایف طولانی، نحوه تأثیر آنها بر تجربه کاربر و کارهایی که باید در مورد آنها انجام دهید، درباره بهینه سازی کارهای طولانی بخوانید.

،

تاریخ انتشار: 6 مارس 2025

Browser Support

  • کروم: 129.
  • لبه: 129.
  • فایرفاکس: پشتیبانی نمی شود.
  • سافاری: پشتیبانی نمی شود.

Source

زمانی که کارهای طولانی موضوع اصلی را مشغول نگه می‌دارند، صفحه کند و بی پاسخ می‌شود و از انجام کارهای مهم دیگر مانند پاسخ دادن به ورودی کاربر جلوگیری می‌کند. در نتیجه، حتی کنترل‌های فرم داخلی ممکن است برای کاربران شکسته به نظر برسند - گویی صفحه ثابت شده است - به اجزای سفارشی پیچیده‌تر اهمیتی نمی‌دهید.

scheduler.yield() راهی برای تسلیم شدن به رشته اصلی است – به مرورگر اجازه می‌دهد هر کار با اولویت بالا را اجرا کند – سپس اجرا را از جایی که متوقف شده ادامه می‌دهد. این یک صفحه را پاسخگوتر نگه می دارد و به نوبه خود به بهبود تعامل با رنگ بعدی (INP) کمک می کند.

scheduler.yield یک API ارگونومیک ارائه می دهد که دقیقاً همان کاری را که می گوید انجام می دهد: اجرای تابعی که فراخوانی می شود در عبارت await scheduler.yield() مکث می کند و به رشته اصلی تسلیم می شود و وظیفه را از بین می برد. اجرای بقیه تابع - که ادامه تابع نامیده می شود - در یک کار حلقه رویداد جدید برنامه ریزی می شود.

async function respondToUserClick() {
  giveImmediateFeedback();
  await scheduler.yield(); // Yield to the main thread.
  slowerComputation();
}

مزیت خاص scheduler.yield این است که ادامه پس از بازده برنامه ریزی شده قبل از اجرای هر کار مشابه دیگری که توسط صفحه در صف قرار گرفته است اجرا شود. ادامه یک کار را بر شروع کارهای جدید اولویت می دهد.

توابعی مانند setTimeout یا scheduler.postTask نیز می‌توانند برای جدا کردن وظایف مورد استفاده قرار گیرند، اما این ادامه‌ها معمولاً پس از هر کار جدید از قبل در صف اجرا می‌شوند و به طور بالقوه خطر تأخیرهای طولانی بین تسلیم شدن به رشته اصلی و تکمیل کار آنها را به همراه دارد.

تداوم بعد از تسلیم اولویت بندی شده است

scheduler.yield بخشی از API زمان‌بندی وظایف اولویت‌دار است. به عنوان توسعه‌دهندگان وب، ما معمولاً در مورد ترتیبی که حلقه رویداد وظایف را بر اساس اولویت‌های صریح اجرا می‌کند، صحبت نمی‌کنیم، اما اولویت‌های نسبی همیشه وجود دارند ، مانند یک درخواست پاسخ به تماس requestIdleCallback که پس از هر پاسخ‌دهی setTimeout در صف اجرا می‌شود، یا یک شنونده رویداد ورودی راه‌اندازی شده که معمولاً قبل از یک کار در صف قرار می‌گیرد، اجرا می‌شود setTimeout(callback, 0) .

زمان‌بندی وظایف اولویت‌دار فقط این موضوع را واضح‌تر می‌کند، و تشخیص اینکه کدام کار قبل از دیگری اجرا می‌شود را آسان‌تر می‌کند و امکان تنظیم اولویت‌ها برای تغییر ترتیب اجرا، در صورت نیاز را فراهم می‌کند.

همانطور که گفته شد، ادامه اجرای یک تابع پس از تسلیم شدن با scheduler.yield() اولویت بیشتری نسبت به شروع کارهای دیگر دارد. مفهوم راهنما این است که ادامه یک کار باید ابتدا اجرا شود، قبل از اینکه به کارهای دیگر بروید. اگر کار کدی است که به خوبی رفتار می‌کند و به‌طور دوره‌ای نمایش داده می‌شود تا مرورگر بتواند کارهای مهم دیگری را انجام دهد (مانند پاسخ به ورودی کاربر)، نباید با اولویت‌بندی پس از سایر کارهای مشابه مجازات شود.

در اینجا یک مثال آورده شده است: دو تابع، در صف برای اجرا در وظایف مختلف با استفاده از setTimeout .

setTimeout(myJob);
setTimeout(someoneElsesJob);

در این مورد، دو فراخوان setTimeout دقیقاً در کنار یکدیگر قرار دارند، اما در یک صفحه واقعی، می‌توانند در مکان‌های کاملاً متفاوتی فراخوانی شوند، مانند یک اسکریپت شخص اول و یک اسکریپت شخص ثالث که به طور مستقل کار را برای اجرا تنظیم می‌کند، یا می‌تواند دو کار از مؤلفه‌های جداگانه باشد که در عمق زمان‌بندی فریمورک شما فعال می‌شوند.

این کار در DevTools چگونه می تواند باشد:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

myJob به عنوان یک کار طولانی علامت گذاری شده است و مرورگر را از انجام هر کار دیگری در حین اجرا مسدود می کند. با فرض اینکه از یک اسکریپت شخص اول است، می توانیم آن را تجزیه کنیم:

function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with setTimeout() to break up long task, then run part2.
  setTimeout(myJobPart2, 0);
}

از آنجایی که myJobPart2 قرار بود با setTimeout در myJob اجرا شود، اما این زمان‌بندی پس از اینکه someoneElsesJob قبلاً برنامه‌ریزی شده بود اجرا می‌شود، نحوه اجرا به این صورت است:

سه کار در پانل عملکرد Chrome DevTools نشان داده شده است. اولی تابع 'myJobPart1' را اجرا می کند، دومی یک کار طولانی است که 'someoneElsesJob' را اجرا می کند، و در نهایت وظیفه سوم اجرای 'myJobPart2' است.

ما کار را با setTimeout تقسیم کرده‌ایم تا مرورگر بتواند در اواسط myJob پاسخگو باشد، اما اکنون بخش دوم myJob فقط پس از پایان کار someoneElsesJob اجرا می‌شود.

در برخی موارد، ممکن است خوب باشد، اما معمولاً این بهینه نیست. myJob در حال تسلیم شدن به موضوع اصلی بود تا مطمئن شود که صفحه می‌تواند به ورودی کاربر پاسخگو باشد، نه اینکه موضوع اصلی را به طور کامل رها کند. در مواردی که someoneElsesJob به خصوص کند است، یا بسیاری از کارهای دیگر غیر از someoneElsesJob نیز برنامه ریزی شده اند، ممکن است زمان زیادی طول بکشد تا نیمه دوم myJob اجرا شود. احتمالاً این هدف توسعه‌دهنده نبود که setTimeout را به myJob اضافه کرد.

scheduler.yield() را وارد کنید، که ادامه هر تابعی را که آن را فراخوانی می کند در یک صف اولویت کمی بالاتر از شروع هر کار مشابه دیگری قرار می دهد. اگر myJob برای استفاده از آن تغییر کند:

async function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with scheduler.yield() to break up long task, then run part2.
  await scheduler.yield();
  myJobPart2();
}

حالا اجرا به صورت زیر است:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

مرورگر هنوز این فرصت را دارد که پاسخگو باشد، اما اکنون ادامه کار myJob بر شروع کار جدید someoneElsesJob اولویت دارد، بنابراین myJob قبل از شروع someoneElsesJob کامل می شود. این به انتظار تسلیم شدن به نخ اصلی برای حفظ پاسخگویی بسیار نزدیکتر است، نه اینکه موضوع اصلی را به طور کامل رها کنید.

وراثت اولویت دار

به‌عنوان بخشی از API برنامه‌ریزی وظایف اولویت‌دار بزرگ‌تر، scheduler.yield() به خوبی با اولویت‌های صریح موجود در scheduler.postTask() ترکیب می‌شود. بدون تعیین اولویت مشخص، یک scheduler.yield() در یک callback scheduler.postTask() اساساً مانند مثال قبلی عمل می کند.

با این حال، اگر اولویتی تنظیم شده باشد، مانند استفاده از اولویت 'background' کم:

async function lowPriorityJob() {
  part1();
  await scheduler.yield();
  part2();
}

scheduler.postTask(lowPriorityJob, {priority: 'background'});

ادامه با اولویتی بالاتر از سایر وظایف 'background' برنامه‌ریزی می‌شود – دریافت ادامه اولویت‌بندی شده مورد انتظار قبل از هر کار 'background' معلق – اما همچنان اولویت کمتری نسبت به سایر وظایف پیش‌فرض یا با اولویت بالا است. کار 'background' باقی می ماند.

این به این معنی است که اگر کار با اولویت پایین را با یک 'background' scheduler.postTask() (یا با requestIdleCallback ) برنامه ریزی کنید، ادامه بعد از scheduler.yield() درون نیز منتظر می ماند تا اکثر وظایف دیگر کامل شوند و رشته اصلی برای اجرا بیکار باشد، که دقیقاً همان چیزی است که شما از بازدهی در یک کار با اولویت پایین می خواهید.

نحوه استفاده از API

در حال حاضر، scheduler.yield() فقط در مرورگرهای مبتنی بر Chromium در دسترس است، بنابراین برای استفاده از آن باید ویژگی‌های شناسایی و بازگشت به روش ثانویه بازدهی برای مرورگرهای دیگر را داشته باشید.

scheduler-polyfill یک polyfill کوچک برای scheduler.postTask و scheduler.yield است که به صورت داخلی از ترکیبی از روش‌ها برای شبیه‌سازی مقدار زیادی از قدرت APIهای زمان‌بندی در مرورگرهای دیگر استفاده می‌کند (اگرچه وراثت اولویت scheduler.yield() پشتیبانی نمی‌شود).

برای کسانی که به دنبال اجتناب از polyfill هستند، یک روش این است که با استفاده از setTimeout() تسلیم شوند و از دست دادن یک ادامه اولویت‌دار را بپذیرند، یا حتی در مرورگرهای پشتیبانی‌نشده در صورتی که قابل قبول نیست، تسلیم نشوند. برای اطلاعات بیشتر، مستندات scheduler.yield() را در بهینه سازی وظایف طولانی ببینید.

اگر می‌خواهید ویژگی scheduler.yield() را شناسایی کنید و خودتان یک نسخه جایگزین اضافه کنید، می‌توانید از انواع wicg-task-scheduling برای بررسی نوع و پشتیبانی IDE نیز استفاده کنید.

بیشتر بدانید

برای کسب اطلاعات بیشتر در مورد API و نحوه تعامل آن با اولویت‌های کار و scheduler.postTask() ، اسناد scheduler.yield() و اولویت‌بندی کارها را در MDN بررسی کنید.

برای کسب اطلاعات بیشتر در مورد وظایف طولانی، نحوه تأثیر آنها بر تجربه کاربر و کارهایی که باید در مورد آنها انجام دهید، درباره بهینه سازی کارهای طولانی بخوانید.

،

تاریخ انتشار: 6 مارس 2025

Browser Support

  • کروم: 129.
  • لبه: 129.
  • فایرفاکس: پشتیبانی نمی شود.
  • سافاری: پشتیبانی نمی شود.

Source

زمانی که کارهای طولانی موضوع اصلی را مشغول نگه می‌دارند، صفحه کند و بی پاسخ می‌شود و از انجام کارهای مهم دیگر مانند پاسخ دادن به ورودی کاربر جلوگیری می‌کند. در نتیجه، حتی کنترل‌های فرم داخلی ممکن است برای کاربران شکسته به نظر برسند - گویی صفحه ثابت شده است - به اجزای سفارشی پیچیده‌تر اهمیتی نمی‌دهید.

scheduler.yield() راهی برای تسلیم شدن به رشته اصلی است – به مرورگر اجازه می‌دهد هر کار با اولویت بالا را اجرا کند – سپس اجرا را از جایی که متوقف شده ادامه می‌دهد. این یک صفحه را پاسخگوتر نگه می دارد و به نوبه خود به بهبود تعامل با رنگ بعدی (INP) کمک می کند.

scheduler.yield یک API ارگونومیک ارائه می دهد که دقیقاً همان کاری را که می گوید انجام می دهد: اجرای تابعی که فراخوانی می شود در عبارت await scheduler.yield() مکث می کند و به رشته اصلی تسلیم می شود و وظیفه را از بین می برد. اجرای بقیه تابع - که ادامه تابع نامیده می شود - در یک کار حلقه رویداد جدید برنامه ریزی می شود.

async function respondToUserClick() {
  giveImmediateFeedback();
  await scheduler.yield(); // Yield to the main thread.
  slowerComputation();
}

مزیت خاص scheduler.yield این است که ادامه پس از بازده برنامه ریزی شده قبل از اجرای هر کار مشابه دیگری که توسط صفحه در صف قرار گرفته است اجرا شود. ادامه یک کار را بر شروع کارهای جدید اولویت می دهد.

توابعی مانند setTimeout یا scheduler.postTask نیز می‌توانند برای جدا کردن وظایف مورد استفاده قرار گیرند، اما این ادامه‌ها معمولاً پس از هر کار جدید از قبل در صف اجرا می‌شوند و به طور بالقوه خطر تأخیرهای طولانی بین تسلیم شدن به رشته اصلی و تکمیل کار آنها را به همراه دارد.

تداوم بعد از تسلیم اولویت بندی شده است

scheduler.yield بخشی از API زمان‌بندی وظایف اولویت‌دار است. به عنوان توسعه‌دهندگان وب، ما معمولاً در مورد ترتیبی که حلقه رویداد وظایف را بر اساس اولویت‌های صریح اجرا می‌کند، صحبت نمی‌کنیم، اما اولویت‌های نسبی همیشه وجود دارند ، مانند یک درخواست پاسخ به تماس requestIdleCallback که پس از هر پاسخ‌دهی setTimeout در صف اجرا می‌شود، یا یک شنونده رویداد ورودی راه‌اندازی شده که معمولاً قبل از یک کار در صف قرار می‌گیرد، اجرا می‌شود setTimeout(callback, 0) .

زمان‌بندی وظایف اولویت‌دار فقط این موضوع را واضح‌تر می‌کند، و تشخیص اینکه کدام کار قبل از دیگری اجرا می‌شود را آسان‌تر می‌کند و امکان تنظیم اولویت‌ها برای تغییر ترتیب اجرا، در صورت نیاز را فراهم می‌کند.

همانطور که گفته شد، ادامه اجرای یک تابع پس از تسلیم شدن با scheduler.yield() اولویت بیشتری نسبت به شروع کارهای دیگر دارد. مفهوم راهنما این است که ادامه یک کار باید ابتدا اجرا شود، قبل از اینکه به کارهای دیگر بروید. اگر کار کدی است که به خوبی رفتار می‌کند و به‌طور دوره‌ای نمایش داده می‌شود تا مرورگر بتواند کارهای مهم دیگری را انجام دهد (مانند پاسخ به ورودی کاربر)، نباید با اولویت‌بندی پس از سایر کارهای مشابه مجازات شود.

در اینجا یک مثال آورده شده است: دو تابع، در صف برای اجرا در وظایف مختلف با استفاده از setTimeout .

setTimeout(myJob);
setTimeout(someoneElsesJob);

در این مورد، دو فراخوان setTimeout دقیقاً در کنار یکدیگر قرار دارند، اما در یک صفحه واقعی، می‌توانند در مکان‌های کاملاً متفاوتی فراخوانی شوند، مانند یک اسکریپت شخص اول و یک اسکریپت شخص ثالث که به طور مستقل کار را برای اجرا تنظیم می‌کند، یا می‌تواند دو کار از مؤلفه‌های جداگانه باشد که در عمق زمان‌بندی فریمورک شما فعال می‌شوند.

این کار در DevTools چگونه می تواند باشد:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

myJob به عنوان یک کار طولانی علامت گذاری شده است و مرورگر را از انجام هر کار دیگری در حین اجرا مسدود می کند. با فرض اینکه از یک اسکریپت شخص اول است، می توانیم آن را تجزیه کنیم:

function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with setTimeout() to break up long task, then run part2.
  setTimeout(myJobPart2, 0);
}

از آنجایی که myJobPart2 قرار بود با setTimeout در myJob اجرا شود، اما این زمان‌بندی پس از اینکه someoneElsesJob قبلاً برنامه‌ریزی شده بود اجرا می‌شود، نحوه اجرا به این صورت است:

سه کار در پانل عملکرد Chrome DevTools نشان داده شده است. اولی تابع 'myJobPart1' را اجرا می کند، دومی یک کار طولانی است که 'someoneElsesJob' را اجرا می کند، و در نهایت وظیفه سوم اجرای 'myJobPart2' است.

ما کار را با setTimeout تقسیم کرده‌ایم تا مرورگر بتواند در اواسط myJob پاسخگو باشد، اما اکنون بخش دوم myJob فقط پس از پایان کار someoneElsesJob اجرا می‌شود.

در برخی موارد، ممکن است خوب باشد، اما معمولاً این بهینه نیست. myJob در حال تسلیم شدن به موضوع اصلی بود تا مطمئن شود که صفحه می‌تواند به ورودی کاربر پاسخگو باشد، نه اینکه موضوع اصلی را به طور کامل رها کند. در مواردی که someoneElsesJob به خصوص کند است، یا بسیاری از کارهای دیگر غیر از someoneElsesJob نیز برنامه ریزی شده اند، ممکن است زمان زیادی طول بکشد تا نیمه دوم myJob اجرا شود. احتمالاً این هدف توسعه‌دهنده نبود که setTimeout را به myJob اضافه کرد.

scheduler.yield() را وارد کنید، که ادامه هر تابعی را که آن را فراخوانی می کند در یک صف اولویت کمی بالاتر از شروع هر کار مشابه دیگری قرار می دهد. اگر myJob برای استفاده از آن تغییر کند:

async function myJob() {
  // Run part 1.
  myJobPart1();
  // Yield with scheduler.yield() to break up long task, then run part2.
  await scheduler.yield();
  myJobPart2();
}

حالا اجرا به صورت زیر است:

دو کار در پانل عملکرد Chrome DevTools نشان داده شده است. هر دو به عنوان کارهای طولانی مشخص می شوند، با تابع "myJob" کل اجرای وظیفه اول و "someoneElsesJob" کل کار دوم را به عهده می گیرد.

مرورگر هنوز این فرصت را دارد که پاسخگو باشد، اما اکنون ادامه کار myJob بر شروع کار جدید someoneElsesJob اولویت دارد، بنابراین myJob قبل از شروع someoneElsesJob کامل می شود. این به انتظار تسلیم شدن به نخ اصلی برای حفظ پاسخگویی بسیار نزدیکتر است، نه اینکه موضوع اصلی را به طور کامل رها کنید.

وراثت اولویت دار

به‌عنوان بخشی از API برنامه‌ریزی وظایف اولویت‌دار بزرگ‌تر، scheduler.yield() به خوبی با اولویت‌های صریح موجود در scheduler.postTask() ترکیب می‌شود. بدون تعیین اولویت مشخص، یک scheduler.yield() در یک callback scheduler.postTask() اساساً مانند مثال قبلی عمل می کند.

با این حال، اگر اولویتی تنظیم شده باشد، مانند استفاده از اولویت 'background' کم:

async function lowPriorityJob() {
  part1();
  await scheduler.yield();
  part2();
}

scheduler.postTask(lowPriorityJob, {priority: 'background'});

ادامه با اولویتی بالاتر از سایر وظایف 'background' برنامه‌ریزی می‌شود – دریافت ادامه اولویت‌بندی شده مورد انتظار قبل از هر کار 'background' معلق – اما همچنان اولویت کمتری نسبت به سایر وظایف پیش‌فرض یا با اولویت بالا است. کار 'background' باقی می ماند.

این به این معنی است که اگر کار با اولویت پایین را با یک 'background' scheduler.postTask() (یا با requestIdleCallback ) برنامه ریزی کنید، ادامه بعد از scheduler.yield() درون نیز منتظر می ماند تا اکثر وظایف دیگر کامل شوند و رشته اصلی برای اجرا بیکار باشد، که دقیقاً همان چیزی است که شما از بازدهی در یک کار با اولویت پایین می خواهید.

نحوه استفاده از API

در حال حاضر، scheduler.yield() فقط در مرورگرهای مبتنی بر Chromium در دسترس است، بنابراین برای استفاده از آن باید ویژگی‌های شناسایی و بازگشت به روش ثانویه بازدهی برای مرورگرهای دیگر را داشته باشید.

scheduler-polyfill یک polyfill کوچک برای scheduler.postTask و scheduler.yield است که به صورت داخلی از ترکیبی از روش‌ها برای شبیه‌سازی مقدار زیادی از قدرت APIهای زمان‌بندی در مرورگرهای دیگر استفاده می‌کند (اگرچه وراثت اولویت scheduler.yield() پشتیبانی نمی‌شود).

برای کسانی که به دنبال اجتناب از polyfill هستند، یک روش این است که با استفاده از setTimeout() تسلیم شوند و از دست دادن یک ادامه اولویت‌دار را بپذیرند، یا حتی در مرورگرهای پشتیبانی‌نشده در صورتی که قابل قبول نیست، تسلیم نشوند. برای اطلاعات بیشتر، مستندات scheduler.yield() را در بهینه سازی وظایف طولانی ببینید.

اگر می‌خواهید ویژگی scheduler.yield() را شناسایی کنید و خودتان یک نسخه جایگزین اضافه کنید، می‌توانید از انواع wicg-task-scheduling برای بررسی نوع و پشتیبانی IDE نیز استفاده کنید.

بیشتر بدانید

برای کسب اطلاعات بیشتر در مورد API و نحوه تعامل آن با اولویت‌های کار و scheduler.postTask() ، اسناد scheduler.yield() و اولویت‌بندی کارها را در MDN بررسی کنید.

برای کسب اطلاعات بیشتر در مورد وظایف طولانی، نحوه تأثیر آنها بر تجربه کاربر و کارهایی که باید در مورد آنها انجام دهید، درباره بهینه سازی کارهای طولانی بخوانید.