Bagaimana cara mengantri mikrotask jika browser tidak mendukung Janji asli?

11

Lebih baik menulis kode yang tidak bergantung pada waktu panggilan balik langsung (seperti microtasks vs macrotasks), tetapi mari kita kesampingkan hal itu untuk sementara waktu.

setTimeoutmengantri macrotask, yang, setidaknya, menunggu untuk memulai sampai semua mikrotasks (dan mikrotasks yang mereka hasilkan) selesai. Ini sebuah contoh:

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

Perilaku a .thenpada Janji yang diselesaikan pada dasarnya berbeda dari perilaku setTimeoutpanggilan balik segera - Janji .thenakan berjalan terlebih dahulu, bahkan jika yang setTimeoutantri dulu. Tetapi hanya browser modern yang mendukung Janji. Bagaimana fungsi khusus microtask dapat diisi dengan benar jika Promisetidak ada?

Jika Anda mencoba meniru .thenmikrotask dengan menggunakan setTimeout, Anda akan mengantri macrotask, bukan mikrotask, sehingga polyfilled yang buruk .thentidak akan berjalan pada waktu yang tepat jika macrotask sudah antri.

Ada solusi yang digunakan MutationObserver, tetapi terlihat jelek, dan bukan untuk apa MutationObserver. Juga, MutationObservertidak didukung pada IE10 dan sebelumnya. Jika seseorang ingin mengantri microtask di lingkungan yang tidak mendukung Janji, apakah ada alternatif yang lebih baik?

(Saya tidak benar - benar mencoba untuk mendukung IE10 - ini hanya latihan teoretis tentang bagaimana microtasks dapat diantrekan tanpa Janji)

Salju
sumber
1
Saya akan menyarankan untuk melihat implementasi janji yang berorientasi pada kinerja, terutama Bluebird. Melihat sejarahnyaschedule.js akan sangat mencerahkan.
Bergi
Sudahkah Anda mencoba melakukan polyfiling the Promise menggunakan sesuatu seperti core-js?
Hugo

Jawaban:

4

Jika kita berbicara tentang IE yang dapat Anda gunakan setImmediate

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

Juga, MutationObserver tidak didukung pada IE10 dan sebelumnya.

setImmediatedidukung pada IE10. Jadi ditambah satu versi IE.
Dan, jika Anda tertarik, plus Node.js.

Ada solusi menggunakan MutationObserver, tetapi terlihat jelek, dan bukan untuk apa MutationObserver.

Ada kemungkinan polyfill lain, berikut beberapa implementasinya: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (yang ini disebutkan dalam MDN) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (yang lebih sederhana)

Dan karena hampir semua polyfill mereka jelek juga.

Tapi bagaimanapun, ini adalah contoh dalam esensinya (menggunakan postMessage), dan saya pikir itu paling jelek dari semua (tetapi juga bukan polyfill yang benar)

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

x00
sumber
Temuan hebat, saya suka semuanya!
Snow
@Snow, omong-omong, Anda mengatakan ini adalah latihan teoretis, tapi, saya masih penasaran, bagaimana Anda menemukan ide ini pada 2019?
x00
Saya hanya ingin tahu bagaimana microtasks dapat diantrekan, benar-benar tidak ada yang lebih spesifik. Saya agak berharap bahwa ada sesuatu yang dibangun ke dalam bahasa yang memberikan akses kepada mereka, selain dari Janji, tetapi sepertinya tidak ada. Semua metode lain terlihat melibatkan memohon keunikan khusus lingkungan yang tidak dirancang untuk hal semacam itu (tapi kebetulan berhasil juga).
Salju
8

Saya melihat bahwa mutationObservercallback menggunakan microtasks, dan untungnya, IE11 mendukungnya, jadi saya punya ide untuk mengantri microtask di IE11 dengan menyimpan callback dan kemudian segera memicu pengamat dengan mengubah elemen:

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

Anda dapat membuka IE11 dan melihat cara kerjanya di atas, tetapi kodenya terlihat aneh.

Salju
sumber