microtask.js 2.8 KB

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