async-writer
Advanced tools
Comparing version 2.0.1 to 2.1.0
@@ -35,3 +35,3 @@ { | ||
}, | ||
"version": "2.0.1" | ||
"version": "2.1.0" | ||
} |
'use strict'; | ||
var EventEmitter = require('events').EventEmitter; | ||
var AsyncTracker = require('./AsyncTracker'); | ||
var StringWriter = require('./StringWriter'); | ||
@@ -10,22 +9,27 @@ var BufferedWriter = require('./BufferedWriter'); | ||
function AsyncStream(writer, parent, global, buffer) { | ||
var finalGlobal; | ||
var events; | ||
function State(stream, originalWriter, events) { | ||
this.originalStream = stream; | ||
this.originalWriter = originalWriter; | ||
this.events = events; | ||
this.remaining = 0; | ||
this.lastCount = 0; | ||
this.last = undefined; // Array | ||
this.ended = false; | ||
this.finished = false; | ||
this.ids = 0; | ||
} | ||
function AsyncStream(global, writer, state, shouldBuffer) { | ||
var finalGlobal = this.attributes = global || {}; | ||
var finalStream; | ||
var tracker; | ||
var originalWriter; | ||
if (parent) { | ||
finalStream = parent.stream; | ||
finalGlobal = parent.global; | ||
events = parent._events; | ||
tracker = parent._tracker; | ||
originalWriter = parent._originalWriter; | ||
if (state) { | ||
finalStream = state.stream; | ||
} else { | ||
finalGlobal = global || (global = {}); | ||
events = global.events /* deprecated */ = writer && writer.on ? writer : new EventEmitter(); | ||
var events = finalGlobal.events /* deprecated */ = writer && writer.on ? writer : new EventEmitter(); | ||
if (!writer) { | ||
writer = new StringWriter(events); | ||
} else if (buffer) { | ||
} else if (shouldBuffer) { | ||
finalStream = writer; | ||
@@ -36,11 +40,8 @@ writer = new BufferedWriter(writer); | ||
finalStream = finalStream || writer; | ||
originalWriter = writer; | ||
tracker = new AsyncTracker(this, originalWriter); | ||
state = new State(this, writer, events); | ||
} | ||
this.global = this.attributes /* legacy */ = finalGlobal; | ||
this._events = events; | ||
this.global = finalGlobal; | ||
this.stream = finalStream; | ||
this._tracker = tracker; | ||
this._originalWriter = originalWriter; | ||
this._state = state; | ||
@@ -50,2 +51,6 @@ this.data = {}; | ||
writer.stream = this; | ||
this._sync = false; | ||
this._stack = undefined; | ||
this._timeoutId = undefined; | ||
} | ||
@@ -64,3 +69,3 @@ | ||
sync: function() { | ||
this._isSync = true; | ||
this._sync = true; | ||
}, | ||
@@ -76,10 +81,12 @@ | ||
getOutput: function () { | ||
return this._originalWriter.toString(); | ||
return this._state.originalWriter.toString(); | ||
}, | ||
beginAsync: function(options) { | ||
if (this._isSync) { | ||
if (this._sync) { | ||
throw new Error('beginAsync() not allowed when using renderSync()'); | ||
} | ||
var state = this._state; | ||
var currentWriter = this.writer; | ||
@@ -92,3 +99,3 @@ | ||
var newWriter = new StringWriter(); | ||
var newStream = new AsyncStream(currentWriter, this); | ||
var newStream = new AsyncStream(this.global, currentWriter, state); | ||
@@ -105,4 +112,45 @@ this.writer = newWriter; | ||
this._tracker.begin(newStream, this, options); | ||
var timeout; | ||
var name; | ||
state.remaining++; | ||
if (options != null) { | ||
if (typeof options === 'number') { | ||
timeout = options; | ||
} else { | ||
timeout = options.timeout; | ||
if (options.last === true) { | ||
if (timeout == null) { | ||
// Don't assign a timeout to last flush fragments | ||
// unless it is explicitly given a timeout | ||
timeout = 0; | ||
} | ||
state.lastCount++; | ||
} | ||
name = options.name; | ||
} | ||
} | ||
if (timeout == null) { | ||
timeout = AsyncStream.DEFAULT_TIMEOUT; | ||
} | ||
newStream.stack = AsyncStream.INCLUDE_STACK ? new Error().stack : null; | ||
newStream.name = name; | ||
if (timeout > 0) { | ||
newStream._timeoutId = setTimeout(function() { | ||
newStream.error(new Error('Async fragment ' + (name ? '(' + name + ') ': '') + 'timed out after ' + timeout + 'ms')); | ||
}, timeout); | ||
} | ||
state.originalStream.emit('beginAsync', { | ||
writer: newStream, | ||
parentWriter: this | ||
}); | ||
return newStream; | ||
@@ -135,3 +183,41 @@ }, | ||
this._tracker.end(this); | ||
var state = this._state; | ||
if (state.finished) { | ||
return; | ||
} | ||
var remaining; | ||
if (this === state.originalStream) { | ||
remaining = state.remaining; | ||
state.ended = true; | ||
} else { | ||
var timeoutId = this._timeoutId; | ||
if (timeoutId) { | ||
clearTimeout(timeoutId); | ||
} | ||
remaining = --state.remaining; | ||
} | ||
if (state.ended) { | ||
if (!state.lastFired && (state.remaining - state.lastCount === 0)) { | ||
state.lastFired = true; | ||
state.lastCount = 0; | ||
state.originalStream.emit('last'); | ||
} | ||
if (remaining === 0) { | ||
state.finished = true; | ||
if (state.originalWriter.end) { | ||
state.originalWriter.end(); | ||
} else { | ||
state.originalStream.emit('finish'); | ||
} | ||
} | ||
} | ||
return this; | ||
@@ -198,3 +284,5 @@ }, | ||
on: function(event, callback) { | ||
if (event === 'finish' && this._originalWriter.finished) { | ||
var state = this._state; | ||
if (event === 'finish' && state.originalWriter.finished) { | ||
callback(); | ||
@@ -204,3 +292,3 @@ return this; | ||
this._events.on(event, callback); | ||
state.events.on(event, callback); | ||
return this; | ||
@@ -210,3 +298,5 @@ }, | ||
once: function(event, callback) { | ||
if (event === 'finish' && this._originalWriter.finished) { | ||
var state = this._state; | ||
if (event === 'finish' && state.originalWriter.finished) { | ||
callback(); | ||
@@ -216,3 +306,3 @@ return this; | ||
this._events.once(event, callback); | ||
state.events.once(event, callback); | ||
return this; | ||
@@ -222,6 +312,8 @@ }, | ||
onLast: function(callback) { | ||
var lastArray = this._last; | ||
var state = this._state; | ||
var lastArray = state.last; | ||
if (!lastArray) { | ||
lastArray = this._last = []; | ||
lastArray = state.last = []; | ||
var i = 0; | ||
@@ -246,3 +338,3 @@ var next = function next() { | ||
emit: function(type, arg) { | ||
var events = this._events; | ||
var events = this._state.events; | ||
switch(arguments.length) { | ||
@@ -263,3 +355,3 @@ case 1: | ||
removeListener: function() { | ||
var events = this._events; | ||
var events = this._state.events; | ||
events.removeListener.apply(events, arguments); | ||
@@ -270,3 +362,3 @@ return this; | ||
prependListener: function() { | ||
var events = this._events; | ||
var events = this._state.events; | ||
events.prependListener.apply(events, arguments); | ||
@@ -277,3 +369,3 @@ return this; | ||
pipe: function(stream) { | ||
this._originalWriter.pipe(stream); | ||
this._state.originalWriter.pipe(stream); | ||
return this; | ||
@@ -283,3 +375,3 @@ }, | ||
error: function(e) { | ||
var stack = this.stack; | ||
var stack = this._stack; | ||
var name = this.name; | ||
@@ -308,4 +400,6 @@ | ||
flush: function() { | ||
if (!this._tracker.finished) { | ||
var stream = this._originalWriter; | ||
var state = this._state; | ||
if (!state.finished) { | ||
var stream = state.originalWriter; | ||
if (stream && stream.flush) { | ||
@@ -325,2 +419,7 @@ stream.flush(); | ||
}, | ||
createOut: function() { | ||
return new AsyncStream(this.global); | ||
}, | ||
captureString: function(func, thisObj) { | ||
@@ -341,4 +440,4 @@ var sb = new StringWriter(); | ||
// alias: | ||
proto.w = AsyncStream.prototype.write; | ||
proto.w = proto.write; | ||
module.exports = AsyncStream; |
@@ -29,3 +29,3 @@ /* | ||
var global; | ||
var buffer; | ||
var shouldBuffer; | ||
@@ -39,10 +39,10 @@ if(arguments.length === 1 && typeof writer.write !== 'function') { | ||
global = options.global; | ||
buffer = options.buffer === true; | ||
shouldBuffer = options.buffer === true; | ||
} | ||
var asyncStream = new AsyncStream( | ||
global, | ||
writer, | ||
null /* Internally used to pass parent */, | ||
global, | ||
buffer); //Create a new context using the writer provided | ||
null /* Internally used to pass state */, | ||
shouldBuffer); //Create a new context using the writer provided | ||
@@ -49,0 +49,0 @@ return asyncStream; |
46559
14
1203