index.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. 'use strict';
  2. class CancelError extends Error {
  3. constructor(reason) {
  4. super(reason || 'Promise was canceled');
  5. this.name = 'CancelError';
  6. }
  7. get isCanceled() {
  8. return true;
  9. }
  10. }
  11. class PCancelable {
  12. static fn(userFn) {
  13. return (...args) => {
  14. return new PCancelable((resolve, reject, onCancel) => {
  15. args.push(onCancel);
  16. userFn(...args).then(resolve, reject);
  17. });
  18. };
  19. }
  20. constructor(executor) {
  21. this._cancelHandlers = [];
  22. this._isPending = true;
  23. this._isCanceled = false;
  24. this._rejectOnCancel = true;
  25. this._promise = new Promise((resolve, reject) => {
  26. this._reject = reject;
  27. const onResolve = value => {
  28. this._isPending = false;
  29. resolve(value);
  30. };
  31. const onReject = error => {
  32. this._isPending = false;
  33. reject(error);
  34. };
  35. const onCancel = handler => {
  36. this._cancelHandlers.push(handler);
  37. };
  38. Object.defineProperties(onCancel, {
  39. shouldReject: {
  40. get: () => this._rejectOnCancel,
  41. set: bool => {
  42. this._rejectOnCancel = bool;
  43. }
  44. }
  45. });
  46. return executor(onResolve, onReject, onCancel);
  47. });
  48. }
  49. then(onFulfilled, onRejected) {
  50. return this._promise.then(onFulfilled, onRejected);
  51. }
  52. catch(onRejected) {
  53. return this._promise.catch(onRejected);
  54. }
  55. finally(onFinally) {
  56. return this._promise.finally(onFinally);
  57. }
  58. cancel(reason) {
  59. if (!this._isPending || this._isCanceled) {
  60. return;
  61. }
  62. if (this._cancelHandlers.length > 0) {
  63. try {
  64. for (const handler of this._cancelHandlers) {
  65. handler();
  66. }
  67. } catch (error) {
  68. this._reject(error);
  69. }
  70. }
  71. this._isCanceled = true;
  72. if (this._rejectOnCancel) {
  73. this._reject(new CancelError(reason));
  74. }
  75. }
  76. get isCanceled() {
  77. return this._isCanceled;
  78. }
  79. }
  80. Object.setPrototypeOf(PCancelable.prototype, Promise.prototype);
  81. module.exports = PCancelable;
  82. module.exports.default = PCancelable;
  83. module.exports.CancelError = CancelError;