如果浏览器不支持本机Promises,如何将微任务排队?


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是第一次排队。但是,只有现代的浏览器才支持Promises。如果不存在,如何正确填充微任务的特殊功能Promise

如果您尝试使用来模仿.then的微setTimeout任务,则会排队执行宏任务,而不是微任务,因此,.then如果已将宏任务排入队列,则填充不良的代码将无法在正确的时间运行。

有一个使用的解决方案MutationObserver,但它看起来很丑陋,不是什么MutationObserver用。另外,MutationObserverIE10及更早版本不支持。如果要在本机不支持Promises的环境中排队微任务,还有其他更好的选择吗?

(我实际上并不是尝试支持IE10-这只是关于如何在没有Promises的情况下将微任务排队的理论练习)


1
我建议您看一下面向性能的Promise实现,尤其是Bluebird。看看schedule.js历史将是有启发性的。
Bergi

您是否尝试过使用core-js之类的方法来对Promise进行过滤?
雨果

Answers:


4

如果我们谈论的是IE,则可以使用 setImmediate

https://developer.mozilla.org/zh-CN/docs/Web/API/Window/setImmediate

另外,IE10及更早版本不支持MutationObserver。

setImmediate在IE10上受支持。因此,再加上一个IE版本。
而且,如果您有兴趣,还可以添加Node.js。

有一个使用MutationObserver的解决方案,但是它看起来很丑,而且不是MutationObserver的目的。

还有其他可能的polyfill,这里有一些实现:https : //github.com/YuzuJS/setImmediate/blob/master/setImmediate.js(在MDN中提到了这一点) https://github.com/taylorhakes/ setAsap / blob / master / setAsap.js(更简单的一个)

几乎所有的polyfill都很难看。

但是无论如何,这本质上是一个示例(使用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');


很棒的发现,我都喜欢!
斯诺

@Snow,顺便说一句,您说的是理论上的练习,但是,我仍然很好奇,您是如何在2019年遇到这个想法的?
x00

我只是想知道微任务如何排队,实际上没有更具体的东西了。我很希望该语言中内置了某种东西,可以提供对它们的访问,而不是Promises,但似乎没有。所有其他方法查找涉及调用该设计并不适合那种事情的环境,特定的怪癖(只是碰巧工作反正)。
降雪

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并看到上面的代码,但是代码看起来很奇怪。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.