ทรัพยากร Dependency แบบไม่พร้อมกันที่มีเงื่อนไข

ฟีเจอร์บนเว็บ: await ระดับบนสุด

await ระดับบนสุดช่วยให้โมดูลทำหน้าที่เป็นฟังก์ชันแบบอะซิงโครนัสได้ ซึ่งหมายความว่าโมดูลสามารถหยุดการดำเนินการชั่วคราวเพื่อรอ Promise วิธีนี้มีประโยชน์อย่างยิ่งสำหรับการโหลดทรัพยากร Dependency แบบไม่พร้อมกันตามเงื่อนไข เช่น Polyfill หรือไลบรารีรองที่มีขนาดใหญ่ เฉพาะเมื่อเบราว์เซอร์ต้องการเท่านั้น

การใช้ await ระดับบนสุดจะช่วยให้คุณรวมตรรกะการโหลดแบบมีเงื่อนไขไว้ภายในโมดูลเดียวได้ ซึ่งจะป้องกันไม่ให้โมดูลผู้บริโภคปลายน้ำทำงานจนกว่าจะโหลดทรัพยากร Dependency จนเสร็จสมบูรณ์และพร้อมใช้งาน

รูปแบบ Polyfill แบบมีเงื่อนไข

แม้ว่า await ระดับบนสุดจะใช้เพื่อโหลดทรัพยากร Dependency แบบไม่พร้อมกันที่เป็นโมดูลตามเงื่อนไขได้ แต่การใช้รูปแบบการโหลดทรัพยากร Dependency ตามเงื่อนไขที่ดีคือการโหลด Polyfill ตามเงื่อนไขสำหรับเบราว์เซอร์ที่ไม่รองรับฟีเจอร์ที่เฉพาะเจาะจง แนวทางนี้จะรวมการตรวจหาฟีเจอร์และการนําเข้าแบบไดนามิกไว้ในโมดูลทรัพยากร Dependency เดียว

ในกรณีต่อไปนี้ ระบบจะโหลด Polyfill ของแอตทริบิวต์ popover แบบมีเงื่อนไขหากไม่มีอยู่ใน HTMLElement.prototype

// conditionally-load-polyfill.js

// Check if the feature is missing before doing work.
// MANDATORY: Prefer checking HTMLElement.prototype over window or document
// when checking for a global DOM attribute or property like popover.
if (!('popover' in HTMLElement.prototype)) {
  // Use top-level await to pause the execution of any module that imports this file 
  // until the polyfill finishes downloading and executing.
  await import('/path/to/popover-polyfill.js');
}

// Export a marker if needed by your application
export const polyfillLoaded = true;
// main.js

// MANDATORY: Because conditionally-load-polyfill.js uses top-level await, 
// this import will block execution of main.js until the polyfill is ready.
import './conditionally-load-polyfill.js';

// Now it is safe to use the feature (e.g., showing a popover)
const myPopover = document.getElementById('my-popover');
if (myPopover) {
  myPopover.showPopover();
}

การจัดลำดับการนำเข้าโมดูลและการหลีกเลี่ยงข้อบกพร่องของ Safari เวอร์ชันก่อน 27

บังคับ: คุณต้องจัดโครงสร้างกราฟโมดูลเพื่อให้ระบบนำเข้าโมดูล await ระดับบนสุดจากจุดแรกเข้าจุดเดียว และดำเนินการให้เสร็จสิ้นก่อนที่โมดูลดาวน์สตรีมจะประเมิน

  • อย่าใส่การนําเข้าแบบคงที่ระดับเดียวกันในไฟล์รายการ (เช่น import './conditionally-load-polyfill.js'; import './app.js';) ตามข้อกําหนดการประเมินโมดูล ECMAScript await ระดับบนสุดจะระงับเฉพาะโมดูลหลักที่นําเข้าเท่านั้น ไม่ใช่การนําเข้าแบบคงที่ระดับเดียวกัน ดังนั้น ./app.js จะประเมินพร้อมกันในเบราว์เซอร์ทั้งหมดก่อนที่ Polyfill จะโหลดเสร็จ
  • อย่าใช้โมดูล await ระดับบนสุดจากโมดูลพี่น้องหลายรายการพร้อมกัน (เช่น มีทั้ง a.js และ b.js นำเข้า ./conditionally-load-polyfill.js แบบคงที่) แม้ว่า Safari 27 จะแก้ไขตัวโหลดโมดูลของ WebKit เพื่อรองรับการนำเข้าโมดูล await ระดับบนสุดพร้อมกันตามข้อกำหนด แต่ Safari 15-26.6 จะทำงานไม่สำเร็จเมื่อโมดูลหลายรายการนำเข้าโมดูลที่มี await ระดับบนสุดพร้อมกัน (ดูความเข้ากันได้ของเบราว์เซอร์ MDN)

แต่ให้เลือกรูปแบบใดรูปแบบหนึ่งจาก 2 รูปแบบต่อไปนี้ โดยขึ้นอยู่กับโครงสร้างโมดูลของคุณ

  1. โมดูลรายการเดียว (แสดงใน main.js ด้านบน): หากโมดูลรายการเรียกใช้ตรรกะการเริ่มต้นที่ขึ้นต่อกันโดยตรง ให้ใช้การนำเข้าแบบคงที่ ./conditionally-load-polyfill.js ที่ด้านบนของโมดูลนั้นและเรียกใช้โค้ดในเนื้อหา
  2. การบูตสแตรปโมดูลแอปพลิเคชันแยกต่างหาก: หากโมดูลรายการมอบสิทธิ์ให้โมดูลแอปพลิเคชันปลายทาง (เช่น ./app.js) ให้เชื่อมโยงการเรียก import() แบบไดนามิกกับ await ระดับบนสุด เพื่อให้ระบบดึงข้อมูลและประเมิน ./app.js หลังจากที่โมดูล Polyfill แก้ไขแล้วเท่านั้น
// main.js

// MANDATORY: Chain dynamic imports with top-level await when bootstrapping separate
// application modules so './app.js' waits for the polyfill to finish loading.
// DO NOT use sibling static imports (`import './conditionally-load-polyfill.js'; import './app.js';`),
// which evaluate concurrently and execute './app.js' before the polyfill is ready.
await import('./conditionally-load-polyfill.js');
await import('./app.js');

กลยุทธ์สำรอง

แม้ว่าเบราว์เซอร์หลักๆ จะรองรับ await ระดับบนสุดพื้นฐานมาตั้งแต่ปี 2021 (Chrome 89, Edge 89, Firefox 89 และ Safari 15) แต่ก็เพิ่งเป็นไปตามข้อกำหนดอย่างสมบูรณ์ใน Safari 27 (ดูความเข้ากันได้ของเบราว์เซอร์ MDN)

  • Safari 15–26.6: ตราบใดที่คุณทำตามรูปแบบจุดแรกเข้าเดียวในส่วนก่อนหน้าเพื่อให้โมดูลพี่น้องหลายรายการไม่นำเข้าโมดูล await ระดับบนสุดพร้อมกัน คุณจะใช้ await ระดับบนสุดได้อย่างปลอดภัยโดยไม่ต้องมีทางเลือกสำรองเพิ่มเติม
  • เบราว์เซอร์เดิม (ก่อนปี 2021): หากแอปพลิเคชันของคุณต้องรองรับเบราว์เซอร์ที่ไม่มีการรองรับ await ระดับบนสุด ให้หลีกเลี่ยง await ระดับบนสุด และรวมการจัดเรียง import() แบบมีเงื่อนไขไว้ในฟังก์ชัน async มาตรฐานหรือเชนสัญญา .then()