Come mettere in coda un microtask se il browser non supporta le promesse native?


11

È meglio scrivere codice che non si basa sul tempismo dei callback immediati (come microtask o macrotask), ma per il momento mettiamolo da parte.

setTimeoutmette in coda un macrotask, che, almeno, attende di iniziare fino al termine di tutti i microtask (e microtask che generano). Ecco un esempio:

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

Il comportamento di una .thenpromessa risolta è fondamentalmente diverso dal comportamento di una setTimeoutrichiamata immediata : la promessa .thenverrà eseguita per prima, anche se setTimeoutprima è stata messa in coda. Ma solo i browser moderni supportano le promesse. In che modo la speciale funzionalità di un microtask può essere adeguatamente polifillata se Promisenon esiste?

Se provi a imitare un .thenmicrotask usando setTimeout, farai la coda di un macrotask, non di un microtask, quindi il malfunzionamento con polifilm .thennon verrà eseguito al momento giusto se un macrotask è già in coda.

C'è una soluzione che utilizza MutationObserver, ma sembra brutta e non MutationObserverè per quello che serve. Inoltre, MutationObservernon è supportato su IE10 e precedenti. Se si desidera mettere in coda un microtask in un ambiente che non supporta nativamente Promesse, ci sono alternative migliori?

(In realtà non sto cercando di supportare IE10 - questo è solo un esercizio teorico su come i microtask possono essere messi in coda senza promesse)


1
Suggerirei di dare un'occhiata alle implementazioni promettenti orientate alle prestazioni, in particolare Bluebird. Dare un'occhiata alla sua storiaschedule.js sarà illuminante.
Bergi

Hai provato a polifilare Promise usando qualcosa come core-js?
Hugo

Risposte:


4

Se stiamo parlando di IE puoi usare setImmediate

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

Inoltre, MutationObserver non è supportato su IE10 e precedenti.

setImmediateè supportato su IE10. Quindi più una versione di IE.
E, se sei interessato, oltre a Node.js.

C'è una soluzione che utilizza MutationObserver, ma sembra brutta e non è per questo che serve MutationObserver.

Esistono altri polyfill possibili, ecco un paio di implementazioni: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (questo è menzionato in MDN) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (uno più semplice)

E come quasi tutti i polyfill sono anche brutti.

Ma comunque, ecco un esempio nella sua essenza (usando postMessage), e penso che sia meno brutto di tutti (ma anche non un vero 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');


Grandi scoperte, mi piacciono tutte!
Snow

@Snow, a proposito, hai detto che è un esercizio teorico, ma, sono ancora curioso, come ti sei imbattuto in questa idea nel 2019?
x00

Mi stavo solo chiedendo come si potessero mettere in coda i microtask, non c'era davvero nulla di più specifico. Speravo in qualche modo che ci fosse qualcosa incorporato nel linguaggio che fornisse l'accesso a loro, oltre a Promesse, ma sembra che non ci sia. Tutti gli altri metodi sembrano coinvolgere invocando stranezze ambiente-specifici che non sono stati progettati per questo genere di cose (ma solo capita al lavoro in ogni caso).
Neve,

8

Ho visto che i mutationObservercallback usano microtask e, fortunatamente, IE11 lo supporta, quindi ho avuto l'idea di mettere in coda un microtask in IE11 salvando il callback e quindi attivando immediatamente l'osservatore cambiando un elemento:

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

Puoi aprire IE11 e vedere quanto sopra funziona, ma il codice sembra strano.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.