microtask.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. 'use strict';
  2. var global = require('../internals/global');
  3. var bind = require('../internals/function-bind-context');
  4. var getOwnPropertyDescriptor = require('../internals/object-get-own-property-descriptor').f;
  5. var macrotask = require('../internals/task').set;
  6. var Queue = require('../internals/queue');
  7. var IS_IOS = require('../internals/engine-is-ios');
  8. var IS_IOS_PEBBLE = require('../internals/engine-is-ios-pebble');
  9. var IS_WEBOS_WEBKIT = require('../internals/engine-is-webos-webkit');
  10. var IS_NODE = require('../internals/engine-is-node');
  11. var MutationObserver = global.MutationObserver || global.WebKitMutationObserver;
  12. var document = global.document;
  13. var process = global.process;
  14. var Promise = global.Promise;
  15. // Node.js 11 shows ExperimentalWarning on getting `queueMicrotask`
  16. var queueMicrotaskDescriptor = getOwnPropertyDescriptor(global, 'queueMicrotask');
  17. var microtask = queueMicrotaskDescriptor && queueMicrotaskDescriptor.value;
  18. var notify, toggle, node, promise, then;
  19. // modern engines have queueMicrotask method
  20. if (!microtask) {
  21. var queue = new Queue();
  22. var flush = function () {
  23. var parent, fn;
  24. if (IS_NODE && (parent = process.domain)) parent.exit();
  25. while (fn = queue.get()) try {
  26. fn();
  27. } catch (error) {
  28. if (queue.head) notify();
  29. throw error;
  30. }
  31. if (parent) parent.enter();
  32. };
  33. // browsers with MutationObserver, except iOS - https://github.com/zloirock/core-js/issues/339
  34. // also except WebOS Webkit https://github.com/zloirock/core-js/issues/898
  35. if (!IS_IOS && !IS_NODE && !IS_WEBOS_WEBKIT && MutationObserver && document) {
  36. toggle = true;
  37. node = document.createTextNode('');
  38. new MutationObserver(flush).observe(node, { characterData: true });
  39. notify = function () {
  40. node.data = toggle = !toggle;
  41. };
  42. // environments with maybe non-completely correct, but existent Promise
  43. } else if (!IS_IOS_PEBBLE && Promise && Promise.resolve) {
  44. // Promise.resolve without an argument throws an error in LG WebOS 2
  45. promise = Promise.resolve(undefined);
  46. // workaround of WebKit ~ iOS Safari 10.1 bug
  47. promise.constructor = Promise;
  48. then = bind(promise.then, promise);
  49. notify = function () {
  50. then(flush);
  51. };
  52. // Node.js without promises
  53. } else if (IS_NODE) {
  54. notify = function () {
  55. process.nextTick(flush);
  56. };
  57. // for other environments - macrotask based on:
  58. // - setImmediate
  59. // - MessageChannel
  60. // - window.postMessage
  61. // - onreadystatechange
  62. // - setTimeout
  63. } else {
  64. // `webpack` dev server bug on IE global methods - use bind(fn, global)
  65. macrotask = bind(macrotask, global);
  66. notify = function () {
  67. macrotask(flush);
  68. };
  69. }
  70. microtask = function (fn) {
  71. if (!queue.head) notify();
  72. queue.add(fn);
  73. };
  74. }
  75. module.exports = microtask;