Jak umieścić w kolejce mikroprobówkę, jeśli przeglądarka nie obsługuje natywnych obietnic?

11

Lepiej jest pisać kod, który nie opiera się na czasie natychmiastowych wywołań zwrotnych (takich jak mikroprocesory kontra makrotaskania), ale odłóżmy to na chwilę na bok.

setTimeoutustawia w kolejce makrotask, który co najmniej czeka, aż rozpocznie się, aż wszystkie mikroprobówki (i mikroprobówki, które spawnują) zakończą się. Oto przykład:

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

Zachowanie się .thenna rozwiązanej obietnicy zasadniczo różni się od zachowania natychmiastowego setTimeoutwywołania zwrotnego - obietnica .thenzostanie uruchomiona jako pierwsza, nawet jeśli setTimeoutpierwsza była w kolejce. Ale tylko nowoczesne przeglądarki obsługują obietnice. Jak można właściwie wypełnić specjalną funkcjonalność mikroprobówki, jeśli Promisenie istnieje?

Jeśli spróbujesz naśladować .thenmikroprocesor za pomocą setTimeout, będziesz ustawiać w kolejce makrotask, a nie mikroprobówkę, więc źle wypełnione pole .thennie uruchomi się we właściwym czasie, jeśli makrotask jest już w kolejce.

Jest takie rozwiązanie MutationObserver, ale wygląda brzydko i nie MutationObserverjest po co . Ponadto MutationObservernie jest obsługiwany w IE10 i wcześniejszych wersjach. Jeśli ktoś chce umieścić w kolejce mikroprobówkę w środowisku, które natywnie nie obsługuje Obietnic, czy są jakieś lepsze alternatywy?

(Nie jestem faktycznie stara się wspierać IE10 - to tylko teoretyczne ćwiczenia na jak microtasks można kolejce bez Promises)

Śnieg
źródło
1
Proponuję rzucić okiem na obiecujące implementacje, które są zorientowane na wydajność, szczególnie Bluebird. Spojrzenie na historięschedule.js będzie pouczające.
Bergi
Czy próbowałeś polifilować obietnicę przy użyciu czegoś takiego jak core-js?
Hugo

Odpowiedzi:

4

Jeśli mówimy o IE, możesz użyć setImmediate

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

Ponadto MutationObserver nie jest obsługiwany w IE10 i wcześniejszych wersjach.

setImmediatejest obsługiwany w IE10. Więc plus jedna wersja IE.
A jeśli jesteś zainteresowany, plus Node.js.

Istnieje rozwiązanie wykorzystujące MutationObserver, ale wygląda brzydko i nie jest tym, do czego służy MutationObserver.

Istnieją inne możliwe wielopełniacze, oto kilka implementacji: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (ten jest wymieniony w MDN) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (prostszy)

I jak prawie wszystkie polypełniacze są również brzydkie.

Ale tak czy inaczej, tutaj jest przykład w swojej istocie (za pomocą postMessage), i myślę, że jest najmniej brzydki ze wszystkich (ale także nie jest to prawdziwa polifill)

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
źródło
Świetne znaleziska, lubię je wszystkie!
Snow
@ Przy okazji, powiedziałeś, że to ćwiczenie teoretyczne, ale nadal jestem ciekawy, jak spotkałeś się z tym pomysłem w 2019 roku?
x00
Zastanawiałem się tylko, jak można ustawić w kolejce mikroprobówki, tak naprawdę nie było nic bardziej szczegółowego. Miałem nadzieję, że istnieje coś wbudowanego w język, który zapewniał do nich dostęp, oprócz Obietnic, ale wygląda na to, że tak nie jest. Wszystkie pozostałe metody polegają na wywoływaniu dziwactw specyficznych dla środowiska, które nie zostały zaprojektowane do tego rodzaju rzeczy (ale po prostu i tak działają).
Snow
8

Widziałem, że mutationObserverwywołania zwrotne używają mikroprocesorów i na szczęście IE11 obsługuje je, więc wpadłem na pomysł, aby ustawić kolejkę w IE11, zapisując wywołanie zwrotne, a następnie natychmiast wyzwalając obserwatora poprzez zmianę elementu:

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

Możesz otworzyć IE11 i zobaczyć, jak powyższe działa, ale kod wygląda dziwnie.

Śnieg
źródło