shimUsing.js 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. 'use strict';
  2. /*
  3. * cls-bluebird
  4. * Function to shim `Promise.using`
  5. *
  6. * `Promise.using()` calls `.then()` and `.lastly` internally which leads to
  7. * unnecessary CLS context binding with a naive patch.
  8. *
  9. * This custom patch intercepts calls to `Promise.all()` (v3) or `Promise.settle()` (v2)
  10. * within `Promise.using()` and patches the resulting promise's `.then`/`.lastly` methods
  11. * so they do not bind callbacks to CLS context.
  12. *
  13. * NB This patch could break if bluebird internals change, but this is covered by the tests.
  14. */
  15. // Modules
  16. var shimmer = require('shimmer');
  17. // Exports
  18. /**
  19. * Patch `Promise.using` method to run callbacks in current CLS context.
  20. *
  21. * @param {Function} Promise - Bluebird Promise constructor to patch
  22. * @param {Object} ns - CLS namespace to bind callbacks to
  23. * @param {boolean} v3 - `true` if bluebird being patched is v3.x
  24. * @returns {undefined}
  25. */
  26. module.exports = function(Promise, ns, v3) {
  27. (v3 ? patchV3 : patchV2)(Promise, ns);
  28. };
  29. // Patch for `Promise.using()` in bluebird v3
  30. function patchV3(Promise, ns) {
  31. var thenOriginal = Promise.prototype.then.__original,
  32. lastlyOriginal = Promise.prototype.lastly.__original;
  33. // Patch method
  34. shimmer.wrap(Promise, 'using', function(usingOriginal) {
  35. return function() {
  36. // Bind `using` callback (last arg)
  37. var argIndex = arguments.length - 1,
  38. callback = arguments[argIndex];
  39. if (typeof callback === 'function') arguments[argIndex] = ns.bind(callback);
  40. // Temporarily patch `Promise.all()`
  41. shimmer.wrap(Promise, 'all', function(allOriginal) {
  42. return function(promises) {
  43. // Remove temporary patch on `Promise.all()`
  44. Promise.all = allOriginal;
  45. // Call original `Promise.all()`
  46. var p = allOriginal.call(this, promises);
  47. // Patch `.then()` method on this promise to not bind callbacks
  48. p.then = function() {
  49. var p = thenOriginal.apply(this, arguments);
  50. // Patch `.lastly()` method on this promise to not bind callbacks
  51. p.lastly = lastlyOriginal;
  52. return p;
  53. };
  54. return p;
  55. };
  56. });
  57. // Call original `Promise.using()` method
  58. return usingOriginal.apply(this, arguments);
  59. };
  60. });
  61. }
  62. // Patch for `Promise.using()` in bluebird v2
  63. function patchV2(Promise, ns) {
  64. var thenOriginal = Promise.prototype.then.__original;
  65. // Patch method
  66. shimmer.wrap(Promise, 'using', function(usingOriginal) {
  67. return function() {
  68. // Bind `using` callback (last arg)
  69. var argIndex = arguments.length - 1,
  70. callback = arguments[argIndex];
  71. if (typeof callback === 'function') arguments[argIndex] = ns.bind(callback);
  72. // Temporarily patch `Promise.settle()`
  73. shimmer.wrap(Promise, 'settle', function(settleOriginal) {
  74. return function(resources) {
  75. // Remove temporary patch on `Promise.settle()`
  76. Promise.settle = settleOriginal;
  77. // Call original `Promise.settle()`
  78. var p = settleOriginal.call(this, resources);
  79. // Patch `.then()` method on this promise to not bind callbacks
  80. p.then = function() {
  81. var p = thenOriginal.apply(this, arguments);
  82. // Patch `.then()` method on this promise to not bind callbacks
  83. p.then = thenOriginal;
  84. return p;
  85. };
  86. return p;
  87. };
  88. });
  89. // Call original `Promise.using()` method
  90. return usingOriginal.apply(this, arguments);
  91. };
  92. });
  93. }