p_cancelable.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. 'use strict';
  2. // Try getting the real promise object from the context, if available. Someone
  3. // could have overridden it in a test.
  4. const Promise = global[Symbol.for('jest-native-promise')] || global.Promise;
  5. class CancelError extends Error {
  6. constructor() {
  7. super('Promise was canceled');
  8. this.name = 'CancelError';
  9. }
  10. }
  11. class PCancelable {
  12. static fn(fn) {
  13. return function() {
  14. const args = [].slice.apply(arguments);
  15. return new PCancelable((onCancel, resolve, reject) => {
  16. args.unshift(onCancel);
  17. fn.apply(null, args).then(resolve, reject);
  18. });
  19. };
  20. }
  21. constructor(executor) {
  22. this._pending = true;
  23. this._canceled = false;
  24. this._promise = new Promise((resolve, reject) => {
  25. this._reject = reject;
  26. return executor(
  27. fn => {
  28. this._cancel = fn;
  29. },
  30. val => {
  31. this._pending = false;
  32. resolve(val);
  33. },
  34. err => {
  35. this._pending = false;
  36. reject(err);
  37. }
  38. );
  39. });
  40. }
  41. then() {
  42. return this._promise.then.apply(this._promise, arguments);
  43. }
  44. catch() {
  45. return this._promise.catch.apply(this._promise, arguments);
  46. }
  47. cancel() {
  48. if (!this._pending || this._canceled) {
  49. return;
  50. }
  51. if (typeof this._cancel === 'function') {
  52. try {
  53. this._cancel();
  54. } catch (err) {
  55. this._reject(err);
  56. }
  57. }
  58. this._canceled = true;
  59. this._reject(new CancelError());
  60. }
  61. get canceled() {
  62. return this._canceled;
  63. }
  64. }
  65. Object.setPrototypeOf(PCancelable.prototype, Promise.prototype);
  66. module.exports = PCancelable;
  67. module.exports.CancelError = CancelError;