rejection-tracking.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. 'use strict';
  2. var Promise = require('./core');
  3. var DEFAULT_WHITELIST = [
  4. ReferenceError,
  5. TypeError,
  6. RangeError
  7. ];
  8. var enabled = false;
  9. exports.disable = disable;
  10. function disable() {
  11. enabled = false;
  12. Promise._onHandle = null;
  13. Promise._onReject = null;
  14. }
  15. exports.enable = enable;
  16. function enable(options) {
  17. options = options || {};
  18. if (enabled) disable();
  19. enabled = true;
  20. var id = 0;
  21. var displayId = 0;
  22. var rejections = {};
  23. Promise._onHandle = function (promise) {
  24. if (
  25. promise._state === 2 && // IS REJECTED
  26. rejections[promise._rejectionId]
  27. ) {
  28. if (rejections[promise._rejectionId].logged) {
  29. onHandled(promise._rejectionId);
  30. } else {
  31. clearTimeout(rejections[promise._rejectionId].timeout);
  32. }
  33. delete rejections[promise._rejectionId];
  34. }
  35. };
  36. Promise._onReject = function (promise, err) {
  37. if (promise._deferredState === 0) { // not yet handled
  38. promise._rejectionId = id++;
  39. rejections[promise._rejectionId] = {
  40. displayId: null,
  41. error: err,
  42. timeout: setTimeout(
  43. onUnhandled.bind(null, promise._rejectionId),
  44. // For reference errors and type errors, this almost always
  45. // means the programmer made a mistake, so log them after just
  46. // 100ms
  47. // otherwise, wait 2 seconds to see if they get handled
  48. matchWhitelist(err, DEFAULT_WHITELIST)
  49. ? 100
  50. : 2000
  51. ),
  52. logged: false
  53. };
  54. }
  55. };
  56. function onUnhandled(id) {
  57. if (
  58. options.allRejections ||
  59. matchWhitelist(
  60. rejections[id].error,
  61. options.whitelist || DEFAULT_WHITELIST
  62. )
  63. ) {
  64. rejections[id].displayId = displayId++;
  65. if (options.onUnhandled) {
  66. rejections[id].logged = true;
  67. options.onUnhandled(
  68. rejections[id].displayId,
  69. rejections[id].error
  70. );
  71. } else {
  72. rejections[id].logged = true;
  73. logError(
  74. rejections[id].displayId,
  75. rejections[id].error
  76. );
  77. }
  78. }
  79. }
  80. function onHandled(id) {
  81. if (rejections[id].logged) {
  82. if (options.onHandled) {
  83. options.onHandled(rejections[id].displayId, rejections[id].error);
  84. } else if (!rejections[id].onUnhandled) {
  85. console.warn(
  86. 'Promise Rejection Handled (id: ' + rejections[id].displayId + '):'
  87. );
  88. console.warn(
  89. ' This means you can ignore any previous messages of the form "Possible Unhandled Promise Rejection" with id ' +
  90. rejections[id].displayId + '.'
  91. );
  92. }
  93. }
  94. }
  95. }
  96. function logError(id, error) {
  97. console.warn('Possible Unhandled Promise Rejection (id: ' + id + '):');
  98. var errStr = (error && (error.stack || error)) + '';
  99. errStr.split('\n').forEach(function (line) {
  100. console.warn(' ' + line);
  101. });
  102. }
  103. function matchWhitelist(error, list) {
  104. return list.some(function (cls) {
  105. return error instanceof cls;
  106. });
  107. }