destroy.js 3.0 KB

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