Làm cách nào để xếp hàng microtask nếu trình duyệt không hỗ trợ Lời hứa gốc?


11

Tốt hơn là viết mã không dựa vào thời gian của các cuộc gọi lại ngay lập tức (như microt Nhiệm vụ so với macrot Nhiệm vụ), nhưng hãy tạm gác chuyện đó sang một bên.

setTimeoutxếp hàng một macrotask, ở mức tối thiểu, chờ để bắt đầu cho đến khi tất cả các microt Nhiệm vụ (và microt Nhiệm vụ mà chúng sinh ra) kết thúc. Đây là một ví dụ:

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');

Hành vi của một .thenLời hứa đã được giải quyết về cơ bản khác với hành vi của một setTimeoutcuộc gọi lại ngay lập tức - Lời hứa .thensẽ chạy trước, ngay cả khi setTimeoutđược xếp hàng trước. Nhưng chỉ có các trình duyệt hiện đại hỗ trợ Promising. Làm thế nào chức năng đặc biệt của microtask có thể được điền đầy đủ nếu Promisekhông tồn tại?

Nếu bạn cố gắng bắt chước .thenmicrotask bằng cách sử dụng setTimeout, bạn sẽ xếp hàng một macrotask, chứ không phải microtask, do đó, polyfills xấu .thensẽ không chạy đúng lúc nếu macrotask đã được xếp hàng.

Có một giải pháp sử dụng MutationObserver, nhưng nó trông xấu, và không phải MutationObserverlà để làm gì . Ngoài ra, MutationObserverkhông được hỗ trợ trên IE10 và trước đó. Nếu một người muốn xếp hàng microtask trong môi trường không hỗ trợ Promise, liệu có lựa chọn nào tốt hơn không?

(Tôi thực sự không cố gắng hỗ trợ IE10 - đây chỉ là một bài tập lý thuyết về cách microt Nhiệm vụ có thể được xếp hàng mà không có Hứa hẹn)


1
Tôi sẽ đề nghị có một cái nhìn về việc triển khai lời hứa theo định hướng hiệu suất, đặc biệt là Bluebird. Nhìn vào lịch sử của nóschedule.js sẽ được khai sáng.
Bergi

Bạn đã thử polyfiling Promise bằng cách sử dụng một cái gì đó như core-js chưa?
Hugo

Câu trả lời:


4

Nếu chúng ta đang nói về IE, bạn có thể sử dụng setImmediate

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

Ngoài ra, MutingObserver không được hỗ trợ trên IE10 trở về trước.

setImmediateđược hỗ trợ trên IE10. Vì vậy, cộng với một phiên bản IE.
Và, nếu bạn quan tâm, cộng với Node.js.

Có một giải pháp sử dụng M mutObserver, nhưng nó trông có vẻ xấu, và đó không phải là M mutObserver dành cho.

Có nhiều polyfill khác, đây là một vài triển khai: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (cái này được đề cập trong MDN) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (một cách đơn giản hơn)

Và vì hầu như tất cả các polyfill đều xấu.

Nhưng dù sao, đây là một ví dụ về bản chất của nó (sử dụng postMessage) và tôi nghĩ nó ít xấu nhất trong tất cả (nhưng cũng không phải là một polyfill thực sự)

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');


Tuyệt vời tìm thấy, tôi thích tất cả!
Tuyết

@Snow, nhân tiện, bạn đã nói đó là một bài tập lý thuyết, nhưng, tôi vẫn tò mò, làm thế nào bạn bắt gặp ý tưởng này vào năm 2019?
x00

Tôi chỉ tự hỏi làm thế nào microt Nhiệm vụ có thể được xếp hàng, thực sự không có gì cụ thể hơn. Tôi đã hy vọng rằng có một thứ gì đó được xây dựng bằng ngôn ngữ cung cấp quyền truy cập cho họ, ngoài Promise, nhưng có vẻ như không có. Tất cả các phương pháp khác có vẻ liên quan đến việc gọi các quirks dành riêng cho môi trường không được thiết kế cho loại điều đó (nhưng dù sao cũng chỉ xảy ra để hoạt động).
Tuyết

8

Tôi thấy rằng các mutationObservercuộc gọi lại sử dụng microt Nhiệm vụ và may mắn thay, IE11 hỗ trợ nó, vì vậy tôi đã có ý tưởng xếp hàng một microtask trong IE11 bằng cách lưu cuộc gọi lại và sau đó kích hoạt ngay lập tức người quan sát bằng cách thay đổi một yếu tố:

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');

Bạn có thể mở IE11 và thấy các hoạt động ở trên, nhưng mã trông lạ.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.