I apologise for the sheer amount of code contained here but I wanted to disclose everything. No matter what I try I cannot get Object.assign()
to assign a whole number to the given key, despite the same operation working perfectly to assign a floating point number on the next line.
This code contains all needed references so it's clunky (part of my debugging kit):
let markers = []
let cumulativeTimes = {}
const randomWholeNumber = (min, max) => Math.floor(Math.random() * (max - min + 1) + min)
const time = (marker) => { markers[marker] = process.hrtime() }
const timeEnd = (marker, cumulative = true) => {
const hrend = process.hrtime(markers[marker])
const precision = 3
const seconds = hrend[0] // already an int
const milliSeconds = +(hrend[1] / 1000000).toFixed(precision) // unary plus converts string result to int
console.log(`Seconds is ${seconds} with type ${typeof(seconds)}`) // outputs "number" - always!
if (cumulative) {
let mark = cumulativeTimes[marker]
mark ? mark.s += seconds : Object.assign(cumulativeTimes, { [marker]: { s: seconds } } ) // <-- It's a trap!
mark ? mark.ms += milliSeconds : Object.assign(cumulativeTimes, { [marker]: { ms: milliSeconds } } )
mark = cumulativeTimes[marker]
console.log(`${mark.s}s, ${mark.ms}ms -- ${marker}`) // outputs undefineds, then NaNs (for seconds)
} else {
console.log(`${seconds}s, ${milliSeconds}ms -- ${marker}`)
}
}
const someLongOp = () => {
time('someLongOp')
return new Promise ( async (resolve) => {
await setTimeout(timeEnd, randomWholeNumber(1000, 5000), 'someLongOp')
resolve()
})
}
const test = async (count) => {
for (let i = 0; i < count; i++) {
await someLongOp()
}
}
test(2)
Sample Output:
Seconds is 2 with type number
undefineds, 993.351ms -- someLongOp
Seconds is 3 with type number
NaNs, 1476.091ms -- someLongOp
Now I understand why the second value is NaN (because on the second run of timeEnd()
the "mark.s" key exists however it references the value undefined
, and performing any arithmetic on undef results in NaN
).
What I don't get is why, when seconds
is a simple unsigned integer which is confirmed to be a number, this value isn't properly assigned on the first run of the timeEnd()
. Even weirder, as we can see from the milliseconds output, this exact same operation works fine for a floating point number... although they are both technically double-precision 64-bit unsigned ints.
Change the default value of cumulative
to false and the seconds are output and displayed as expected, so I'm 95% sure it's something going on during the Object.assign()
part.
Will definitely award a bounty to this once it qualifies... looking forward to understanding what on earth is happening!