Wie stelle ich eine Mikrotask in die Warteschlange, wenn der Browser keine nativen Versprechen unterstützt?

11

Es ist besser, Code zu schreiben, der nicht vom Zeitpunkt sofortiger Rückrufe abhängt (wie Mikrotasks oder Makrotasks), aber lassen Sie uns dies für den Moment beiseite legen.

setTimeoutStellt eine Makrotask in die Warteschlange, die mindestens auf den Start wartet, bis alle Mikrotasks (und die von ihnen erzeugten Mikrotasks) abgeschlossen sind. Hier ist ein Beispiel:

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

Das Verhalten .theneines aufgelösten Versprechens unterscheidet sich grundlegend vom Verhalten eines sofortigen setTimeoutRückrufs - das Versprechen .thenwird zuerst ausgeführt, selbst wenn das zuerst setTimeoutin die Warteschlange gestellt wurde. Aber nur moderne Browser unterstützen Versprechen. Wie kann die spezielle Funktionalität einer Mikrotask ordnungsgemäß polygefüllt werden, wenn Promisesie nicht vorhanden ist?

Wenn Sie versuchen, die .thenMikrotask eines Benutzers mithilfe von zu imitieren setTimeout, stellen Sie eine Makrotask in die Warteschlange, keine Mikrotask, sodass die schlecht gefüllte Mikrotask .thennicht zum richtigen Zeitpunkt ausgeführt wird, wenn eine Makrotask bereits in der Warteschlange steht.

Es gibt eine Lösung MutationObserver, aber sie sieht hässlich aus und ist nicht das, wofür sie gedacht MutationObserverist. Wird MutationObserverauch von IE10 und früheren Versionen nicht unterstützt. Wenn man eine Mikrotask in einer Umgebung in die Warteschlange stellen möchte, die Promises nicht nativ unterstützt, gibt es bessere Alternativen?

(Ich versuche eigentlich nicht , IE10 zu unterstützen - dies ist nur eine theoretische Übung darüber, wie Mikrotasks ohne Versprechen in die Warteschlange gestellt werden können.)

Schnee
quelle
1
Ich würde vorschlagen, sich vielversprechende Implementierungen anzusehen, die leistungsorientiert sind, insbesondere Bluebird. Ein Blick auf die Geschichteschedule.js wird aufschlussreich sein.
Bergi
Haben Sie versucht, das Versprechen mit so etwas wie core-js zu polyfilen?
Hugo

Antworten:

4

Wenn wir über IE sprechen, können Sie verwenden setImmediate

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

Außerdem wird MutationObserver unter IE10 und früheren Versionen nicht unterstützt.

setImmediatewird auf IE10 unterstützt. Also plus eine IE-Version.
Und wenn Sie interessiert sind, plus Node.js.

Es gibt eine Lösung mit MutationObserver, aber sie sieht hässlich aus und ist nicht das, wofür MutationObserver gedacht ist.

Es gibt andere mögliche Polyfills. Hier einige Implementierungen: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (diese wird in MDN erwähnt) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (einfacher)

Und wie fast alle Polyfills sind sie auch hässlich.

Aber hier ist ein Beispiel in seiner Essenz (mit postMessage), und ich denke, es ist am wenigsten hässlich von allen (aber auch keine echte Polyfüllung)

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
quelle
Tolle Fundstücke, ich mag sie alle!
Schnee
@Snow, übrigens, Sie sagten, es sei eine theoretische Übung, aber ich bin immer noch neugierig, wie Sie 2019 auf diese Idee gekommen sind?
x00
Ich habe mich nur gefragt, wie Mikrotasks in die Warteschlange gestellt werden können. Es gab wirklich nichts Spezifischeres. Ich hatte gehofft, dass in die Sprache etwas eingebaut ist, das ihnen Zugang gewährt, außer Versprechen, aber es sieht so aus, als gäbe es keine. Alle anderen Methoden suchen einzubeziehen umgebungsspezifische Macken Aufruf , die nicht für diese Art von Dingen entworfen wurden (aber nur geschehen , um Arbeit sowieso).
Schnee
8

Ich habe gesehen, dass mutationObserverRückrufe Mikrotasks verwenden, und zum Glück unterstützt IE11 diese. Daher kam mir die Idee, eine Mikrotask in IE11 in die Warteschlange zu stellen, indem der Rückruf gespeichert und der Beobachter dann sofort durch Ändern eines Elements ausgelöst wird:

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

Sie können IE11 öffnen und sehen, dass das oben genannte funktioniert, aber der Code sieht seltsam aus.

Schnee
quelle