Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

use faster timers #1908

Merged
merged 16 commits into from
Feb 5, 2023
Prev Previous commit
Next Next commit
fixup
  • Loading branch information
ronag committed Feb 4, 2023
commit 386a8acad6b1518b78b2cb072a6c68a3500185e6
98 changes: 37 additions & 61 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,48 +84,6 @@ try {
channels.connected = { hasSubscribers: false }
}

let fastNow = Date.now()
const fastTimers = new Set()
const fastNowInterval = setInterval(() => {
fastNow = Date.now()

// TODO (perf): This can probably be optimized.
for (const timer of fastTimers) {
if (fastNow >= timer.expires) {
timer.expires = 0
timer.callback(timer.opaque)
}
}
}, 1e3)
if (fastNowInterval.unref) {
fastNowInterval.unref()
}

function setFastTimeout (callback, delay, opaque) {
const timer = {
callback,
delay,
expires: fastNow + delay,
opaque
}

fastTimers.add(timer)

return timer
}

function refreshFastTimeout (timer) {
if (timer) {
timer.expires = fastNow + timer.delay
}
}

function clearFastTimeout (timer) {
if (timer) {
fastTimers.delete(timer)
}
}

class Client extends DispatcherBase {
constructor (url, {
interceptors,
Expand Down Expand Up @@ -462,9 +420,14 @@ class Parser {
this.ptr = this.llhttp.llhttp_alloc(constants.TYPE.RESPONSE)
this.client = client
this.socket = socket
this.timeout = null
this.timeoutValue = null

this.timeoutActive = false
this.timeoutValue = 0
this.timeoutType = null
this.timeoutExpires = 0
this.timeoutNow = Date.now()
this.timeoutInterval = null

this.statusCode = null
this.statusText = ''
this.upgrade = false
Expand All @@ -485,29 +448,42 @@ class Parser {

setTimeout (value, type) {
this.timeoutType = type
if (value !== this.timeoutValue) {
clearFastTimeout(this.timeout)
if (value) {
this.timeout = setFastTimeout(onParserTimeout, value, this)
// istanbul ignore else: only for jest
if (this.timeout.unref) {
this.timeout.unref()
}
} else {
this.timeout = null
}
this.timeoutValue = value
} else {
this.refreshTimeout()
this.timeoutValue = value
this.timeoutActive = true
this.refreshTimeout()
}

clearTimeout () {
this.timeoutActive = false

if (this.timeoutInterval) {
clearInterval(this.timeoutInterval)
this.timeoutInterval = null
}
}

refreshTimeout () {
refreshFastTimeout(this.timeout)
if (this.timeoutActive) {
this.startInterval()
this.timeoutExpires = this.timeoutNow + this.timeoutValue
}
}

clearTimeout () {
clearFastTimeout(this.timeout)
startInterval () {
if (!this.timeoutInterval) {
this.timeoutNow = Date.now()
this.timeoutInterval = setInterval(() => {
this.timeoutNow = Date.now()
if (this.timeoutActive && this.timeoutExpires < this.timeoutNow) {
this.timeoutActive = false
onParserTimeout.call(this)
}
}, 1e3)

if (this.timeoutInterval.unref) {
this.timeoutInterval.unref()
}
}
}

resume () {
Expand Down