destroy.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. // undocumented cb() API, needed for core, not for public API
  3. function destroy(err, cb) {
  4. var _this = this;
  5. var readableDestroyed = this._readableState && this._readableState.destroyed;
  6. var writableDestroyed = this._writableState && this._writableState.destroyed;
  7. if (readableDestroyed || writableDestroyed) {
  8. if (cb) {
  9. cb(err);
  10. } else if (err) {
  11. if (!this._writableState) {
  12. process.nextTick(emitErrorNT, this, err);
  13. } else if (!this._writableState.errorEmitted) {
  14. this._writableState.errorEmitted = true;
  15. process.nextTick(emitErrorNT, this, err);
  16. }
  17. }
  18. return this;
  19. }
  20. // we set destroyed to true before firing error callbacks in order
  21. // to make it re-entrance safe in case destroy() is called within callbacks
  22. if (this._readableState) {
  23. this._readableState.destroyed = true;
  24. }
  25. // if this is a duplex stream mark the writable part as destroyed as well
  26. if (this._writableState) {
  27. this._writableState.destroyed = true;
  28. }
  29. this._destroy(err || null, function (err) {
  30. if (!cb && err) {
  31. if (!_this._writableState) {
  32. process.nextTick(emitErrorAndCloseNT, _this, err);
  33. } else if (!_this._writableState.errorEmitted) {
  34. _this._writableState.errorEmitted = true;
  35. process.nextTick(emitErrorAndCloseNT, _this, err);
  36. } else {
  37. process.nextTick(emitCloseNT, _this);
  38. }
  39. } else if (cb) {
  40. process.nextTick(emitCloseNT, _this);
  41. cb(err);
  42. } else {
  43. process.nextTick(emitCloseNT, _this);
  44. }
  45. });
  46. return this;
  47. }
  48. function emitErrorAndCloseNT(self, err) {
  49. emitErrorNT(self, err);
  50. emitCloseNT(self);
  51. }
  52. function emitCloseNT(self) {
  53. if (self._writableState && !self._writableState.emitClose) return;
  54. if (self._readableState && !self._readableState.emitClose) return;
  55. self.emit('close');
  56. }
  57. function undestroy() {
  58. if (this._readableState) {
  59. this._readableState.destroyed = false;
  60. this._readableState.reading = false;
  61. this._readableState.ended = false;
  62. this._readableState.endEmitted = false;
  63. }
  64. if (this._writableState) {
  65. this._writableState.destroyed = false;
  66. this._writableState.ended = false;
  67. this._writableState.ending = false;
  68. this._writableState.finalCalled = false;
  69. this._writableState.prefinished = false;
  70. this._writableState.finished = false;
  71. this._writableState.errorEmitted = false;
  72. }
  73. }
  74. function emitErrorNT(self, err) {
  75. self.emit('error', err);
  76. }
  77. function errorOrDestroy(stream, err) {
  78. // We have tests that rely on errors being emitted
  79. // in the same tick, so changing this is semver major.
  80. // For now when you opt-in to autoDestroy we allow
  81. // the error to be emitted nextTick. In a future
  82. // semver major update we should change the default to this.
  83. var rState = stream._readableState;
  84. var wState = stream._writableState;
  85. if (rState && rState.autoDestroy || wState && wState.autoDestroy) stream.destroy(err);else stream.emit('error', err);
  86. }
  87. module.exports = {
  88. destroy: destroy,
  89. undestroy: undestroy,
  90. errorOrDestroy: errorOrDestroy
  91. };