diff --git a/package-lock.json b/package-lock.json index 31c0cd3c..187500bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "statuses": "^2.0.2", "tseep": "^1.3.1", "type-is": "^2.0.1", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.63.0", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.64.0", "vary": "^1.1.2" }, "devDependencies": { @@ -8443,8 +8443,8 @@ } }, "node_modules/uWebSockets.js": { - "version": "20.63.0", - "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#d584e6247998f725e86db77130de139eda936473", + "version": "20.64.0", + "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#09c62a4f6dd5fa2e8103f7409949e9eff53ba4ca", "license": "Apache-2.0" }, "node_modules/validate-npm-package-license": { diff --git a/package.json b/package.json index 941a2c4b..2ee20a79 100644 --- a/package.json +++ b/package.json @@ -64,7 +64,7 @@ "statuses": "^2.0.2", "tseep": "^1.3.1", "type-is": "^2.0.1", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.63.0", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.64.0", "vary": "^1.1.2" }, "devDependencies": { diff --git a/src/response.js b/src/response.js index cc081ab2..49184f08 100644 --- a/src/response.js +++ b/src/response.js @@ -71,9 +71,7 @@ class Socket extends EventEmitter { module.exports = class Response extends Writable { #socket = null; #ended = false; - #pendingChunks = []; - #lastWriteChunkTime = 0; - #writeTimeout = null; + #pendingCallback = null; req; constructor(res, req, app) { super(); @@ -157,36 +155,21 @@ module.exports = class Response extends Writable { } if (this.chunkedTransfer) { - this.#pendingChunks.push(chunk); - const size = this.#pendingChunks.reduce((acc, chunk) => acc + chunk.byteLength, 0); - const now = performance.now(); - // the first chunk is sent immediately (!this.#lastWriteChunkTime) - // the other chunks are sent when watermark is reached (size >= HIGH_WATERMARK) - // or if elapsed 50ms of last send (now - this.#lastWriteChunkTime > 50) - if (!this.#lastWriteChunkTime || size >= HIGH_WATERMARK || now - this.#lastWriteChunkTime > 50) { - this._res.write(Buffer.concat(this.#pendingChunks, size)); - this.#pendingChunks = []; - this.#lastWriteChunkTime = now; - if(this.#writeTimeout) { - clearTimeout(this.#writeTimeout); - this.#writeTimeout = null; - } - } else if(!this.#writeTimeout) { - this.#writeTimeout = setTimeout(() => { - this.#writeTimeout = null; - if(!this.finished && !this.aborted) this._res.cork(() => { - if(this.#pendingChunks.length) { - const size = this.#pendingChunks.reduce((acc, chunk) => acc + chunk.byteLength, 0); - this._res.write(Buffer.concat(this.#pendingChunks, size)); - this.#pendingChunks = []; - this.#lastWriteChunkTime = performance.now(); - } - }); - }, 50); - this.#writeTimeout.unref(); + const ok = this._res.write(chunk); + if (ok) { + this.writingChunk = false; + callback(null); + } else { + this.#pendingCallback = callback; + this._res.onWritable(() => { + if (this.aborted || this.finished) return true; + const cb = this.#pendingCallback; + this.#pendingCallback = null; + this.writingChunk = false; + if (cb) cb(null); + return true; + }); } - this.writingChunk = false; - callback(null); } else { const lastOffset = this._res.getWriteOffset(); const [ok, done] = this._res.tryEnd(chunk, this.totalSize); @@ -312,11 +295,6 @@ module.exports = class Response extends Writable { if(!data && contentLength) { this._res.endWithoutBody(contentLength.toString()); } else { - if(this.#pendingChunks.length) { - this._res.write(Buffer.concat(this.#pendingChunks)); - this.#pendingChunks = []; - this.lastWriteChunkTime = 0; - } if(data instanceof Buffer) { data = data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength); }