Як встановити чергу на мікрозадачу, якщо браузер не підтримує нативних Обіцянь?


11

Краще написати код, який не покладається на терміни негайних зворотних викликів (наприклад, мікрозадачі проти макрозадач), але давайте відкладемо це на час.

setTimeoutчерги макрозадачі, яка, як мінімум, чекає запуску, поки всі мікротеки (і мікрозадачі, які вони нерестуються) закінчуються. Ось приклад:

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

Поведінка .thenна вирішеному Обіцянні принципово відрізняється від поведінки негайного setTimeoutзворотного виклику - Обіцянок .thenбуде виконуватися першим, навіть якщо setTimeoutспочатку було поставлено чергу. Але обіцянки підтримують лише сучасні браузери. Як особливу функціональність мікротеки можна правильно заповнити, якщо її Promiseнемає?

Якщо ви спробуєте наслідувати .thenмікротеки 's, використовуючи setTimeout, ви ставите в чергу макротаків, а не мікротаків, тому погано заповнений .thenне буде запущений у потрібний час, якщо макросклад уже в черзі.

Є рішення, яке використовує MutationObserver, але воно виглядає некрасиво, і не для чого MutationObserver. Також MutationObserverне підтримується в IE10 і раніше. Якщо ви хочете встановити чергу з мікрозадачею в середовищі, яке не підтримує обіцянок, чи є кращі альтернативи?

насправді не намагаюся підтримувати IE10 - це лише теоретична вправа щодо того, як мікрозадачі можна ставити в чергу без обіцянок)


1
Я б запропонував ознайомитись з реалізаціями обіцянок, орієнтованими на ефективність, особливо Bluebird. Ознайомитися з історією йогоschedule.js буде освічуючо.
Бергі

Ви спробували поліфілювати Обіцянку, використовуючи щось на зразок core-js?
Гюго

Відповіді:


4

Якщо ми говоримо про IE, ви можете використовувати setImmediate

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

Також MutationObserver не підтримується в IE10 і раніше.

setImmediateпідтримується в IE10. Так плюс одна версія IE.
І, якщо ви зацікавлені, плюс Node.js.

Існує рішення, що використовує MutationObserver, але воно виглядає некрасиво, і це не те, для чого призначений MutationObserver.

Є й інші можливі поліполи, ось кілька реалізацій: https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js (про це згадується в MDN) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js (більш простий)

І як майже всі поліфіли, вони також некрасиві.

Але в будь-якому випадку, ось приклад за своєю суттю (використовуючи postMessage), і я вважаю, що це найменш некрасиво з усіх (але також не є справжнім 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');


Чудові знахідки, мені всі вони подобаються!
Сніг

@ Знаєте, до речі, ви сказали, що це теоретична вправа, але, мені все одно цікаво, як ви натрапили на цю ідею в 2019 році?
x00

Мені було просто цікаво, як мікрозадачі можуть бути в черзі, насправді нічого більш конкретного не було. Я сподівався, що в мові щось вбудоване, що забезпечує доступ до них, крім Обіцянь, але, схоже, немає. Всі інші методи виглядають залучати застосування екологічно конкретні примх , які не були призначені для такого роду речей (але тільки трапляються працювати в будь-якому випадку).
Сніг

8

Я бачив, що mutationObserverзворотні дзвінки використовують мікрозадачі, і, на щастя, IE11 підтримує це, тому у мене виникла ідея встановити чергу в мікрозадачу в IE11, зберігаючи зворотний виклик, а потім негайно запускаючи спостерігача шляхом зміни елемента:

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

Ви можете відкрити IE11 і побачити, як описано вище, але код виглядає дивно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.