จะจัดคิว microtask ได้อย่างไรถ้าเบราว์เซอร์ไม่สนับสนุน Promises ดั้งเดิม


11

ควรเขียนโค้ดที่ไม่ต้องพึ่งพาช่วงเวลาของการโทรกลับทันที (เช่น microtasks vs macrotasks) แต่ลองทิ้งไว้สักครู่

setTimeoutรอคิว macrotask ซึ่งอย่างน้อยก็รอให้เริ่มจนกว่า microtasks ทั้งหมด (และ microtasks ที่วางไข่) จะเสร็จสิ้น นี่คือตัวอย่าง:

console.log('Macrotask queued');
setTimeout(function() {
  console.log('Macrotask running');
});
Promise.resolve()
  .then(function() {
    console.log('Microtask running');
  });
console.log('Microtask queued');
console.log('Last line of script');

พฤติกรรมของ a .thenon the Promise ที่ได้รับการแก้ไขนั้นแตกต่างจากพฤติกรรมของการsetTimeoutโทรกลับทันที- Promise .thenจะทำงานก่อนแม้ว่าจะsetTimeoutถูกจัดคิวก่อน แต่เบราว์เซอร์ที่ทันสมัยเท่านั้นที่สนับสนุนสัญญา วิธีสามารถพิเศษการทำงานของ microtask คนหนึ่ง polyfilled ถูกต้องหากPromiseไม่อยู่?

หากคุณพยายามเลียนแบบ.thenmicrotask โดยใช้setTimeoutคุณจะต้องรอคิว macrotask ไม่ใช่ microtask ดังนั้นโพลีฟิลที่ไม่ดี.thenจะไม่ทำงานในเวลาที่ถูกต้องหาก macrotask ถูกจัดคิวไว้แล้ว

มีวิธีแก้ปัญหาโดยใช้ MutationObserverแต่ดูน่าเกลียดและไม่ใช่MutationObserverสำหรับ นอกจากนี้MutationObserverไม่รองรับ IE10 และรุ่นก่อนหน้า หากใครต้องการคิว microtask ในสภาพแวดล้อมที่ไม่สนับสนุน Promises มีทางเลือกอื่นที่ดีกว่านี้หรือไม่?

(ฉันไม่จริงพยายามสนับสนุน IE10 - นี่เป็นเพียงแบบฝึกหัดทางทฤษฎีว่า microtasks สามารถเข้าคิวโดยไม่มีสัญญาได้อย่างไร)


1
ฉันขอแนะนำให้ดูการใช้งานสัญญาที่เน้นประสิทธิภาพโดยเฉพาะ Bluebird การดูประวัติschedule.jsความเป็นมาของมันจะเป็นความกระจ่าง
Bergi

คุณลอง polyfiling the Promise โดยใช้ core-js ไหม?
Hugo

คำตอบ:


4

หากเรากำลังพูดถึง IE คุณสามารถใช้ setImmediate

https://developer.mozilla.org/en-US/docs/Web/API/Window/setImmediate

นอกจากนี้ MutationObserver ไม่รองรับ IE10 และก่อนหน้านี้

setImmediateรองรับ IE10 ดังนั้นบวกหนึ่งเวอร์ชัน IE
และถ้าคุณมีความสนใจรวมทั้ง Node.js

มีวิธีแก้ปัญหาโดยใช้ MutationObserver แต่มันดูน่าเกลียดและไม่ใช่สิ่งที่ MutationObserver ใช้

มี polyfills อื่น ๆ ที่เป็นไปได้ต่อไปนี้คือการใช้งานสองอย่าง: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (อันนี้ถูกกล่าวถึงใน MDN) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (อันที่ง่ายกว่านี้)

และพอลิฟิลเกือบทั้งหมดก็น่าเกลียดเช่นกัน

แต่ต่อไปนี้เป็นตัวอย่างในสาระสำคัญของมัน (โดยใช้ postMessage) และฉันคิดว่ามันน่าเกลียดที่สุดของทั้งหมด (แต่ยังไม่ใช่ polyfill จริง)

var setImmediate = (function() {
  var queue = [];

  function on_message(e) {
    if(e.data === "setImmediateMsg") queue.pop()()
  }

  if(window.addEventListener) { // IE9+
    window.addEventListener('message', on_message)
  } else { // IE8
    window.attachEvent('onmessage', on_message)
  }

  return function(fn) {
    queue.unshift(fn)
    window.postMessage("setImmediateMsg", "*")
  }
}())

setTimeout(function() {
  console.log('Macrotask running');
});
console.log('Macrotask queued');
setImmediate(function() {
  console.log('Microtask running');
});
console.log('Microtask queued');
console.log('Last line of script');


พบมากฉันชอบพวกเขาทั้งหมด!
หิมะ

@Snow โดยวิธีการที่คุณบอกว่ามันเป็นแบบฝึกหัดทางทฤษฎี แต่ฉันยังคงอยากรู้อยากเห็นว่าคุณเจอความคิดนี้ในปี 2019 ได้อย่างไร?
x00

ฉันแค่สงสัยว่าจะจัดคิวงานไมโครได้อย่างไรไม่มีอะไรพิเศษอีกแล้ว ฉันหวังว่าจะมีบางสิ่งที่สร้างขึ้นในภาษาที่ให้การเข้าถึงแก่พวกเขานอกเหนือจากที่สัญญา แต่ดูเหมือนว่าจะไม่มี วิธีการอื่น ๆ ทั้งหมดดูเหมือนจะเกี่ยวข้องกับการเรียกใช้นิสัยเฉพาะสภาพแวดล้อมที่ไม่ได้ออกแบบมาสำหรับสิ่งนั้น (แต่เพิ่งเกิดขึ้นเพื่อทำงานต่อไป)
หิมะ

8

ฉันเห็นว่าการmutationObserverโทรกลับใช้ microtasks และโชคดีที่ IE11 รองรับดังนั้นฉันจึงมีความคิดที่จะจัดคิว microtask ใน IE11 ด้วยการบันทึกการโทรกลับแล้วเรียกผู้สังเกตการณ์โดยเปลี่ยนองค์ประกอบทันที:

var weirdQueueMicrotask = (function() {
  var elementThatChanges = document.createElement('div');
  var callback;
  var bool = false;
  new MutationObserver(function() {
    callback();
  }).observe(elementThatChanges, { childList: true });
  return function(callbackParam) {
    callback = callbackParam;
    elementThatChanges.textContent = bool = !bool;
  };
})();

setTimeout(function() {
  console.log('Macrotask running');
});
console.log('Macrotask queued');
weirdQueueMicrotask(function() {
  console.log('Microtask running');
});
console.log('Microtask queued');
console.log('Last line of script');

คุณสามารถเปิด IE11 และดูการทำงานข้างต้น แต่รหัสดูแปลก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.