Skip to content

Instantly share code, notes, and snippets.

@SeLub
Last active July 22, 2024 11:57
Show Gist options
  • Save SeLub/1cbc6b5ccb0dfde8fd024e45b480e2b2 to your computer and use it in GitHub Desktop.
Save SeLub/1cbc6b5ccb0dfde8fd024e45b480e2b2 to your computer and use it in GitHub Desktop.

Task

console.log '1' after 1 second,
'2' after 2 seconds and
'3' after 3 seconds after start of the program.

setTimeout

The delay parameter only guarantees that your callback will not execute before that time has elapsed. Other queued tasks or operations could delay it further than the specified time.

const startTime = process.hrtime();

console.log('startTime: ', startTime);
for (let i = 1; i < 4; i++) {
    setTimeout(() => {
        console.log('Message ' + i + ' ', process.hrtime());
    }, i * 1000);
}

Output

startTime: [ 20341, 488209050 ]
Message 1 [ 20342, 499922394 ]
Message 2 [ 20343, 498388755 ]
Message 3 [ 20344, 498487014 ]

console.log('startTime: ', startTime);
for (let i = 1; i < 4; i++) {
    setTimeout(() => {
        console.log('Message ' + i + ' ', process.hrtime(startTime));
    }, i * 1000);
}

Output

startTime: [ 20482, 505385747 ]
Message 1 [ 1, 13938178 ]
Message 2 [ 2, 13741552 ]
Message 3 [ 3, 13861540 ]


for (let i = 1; i < 4; i++) {
    setTimeout(() => {
        console.log('Message ' + i + ' ', process.uptime());
    }, i * 1000);
}

Output

Message 1 1.10126115
Message 2 2.102194643
Message 3 3.102512365

setInterval

const startTime = process.hrtime();
console.log('startTime: ', startTime);

let i = 1;
const interval = setInterval(() => {
    console.log('Message ' + i + ' ', process.hrtime());
    i++;
    if (i > 3) {
        clearInterval(interval);
    }
}, 1000);

Output

startTime: [ 21511, 206821155 ]
Message 1 [ 21512, 217929990 ]
Message 2 [ 21513, 218730640 ]
Message 3 [ 21514, 218790140 ]

const startTime = process.hrtime();
console.log('startTime: ', startTime);

let i = 1;
const interval = setInterval(() => {
    console.log('Message ' + i + ' ', process.hrtime(startTime));
    i++;
    if (i > 3) {
        clearInterval(interval);
    }
}, 1000);

Output

startTime: [ 21356, 295521886 ] Message 1 [ 1, 10849822 ] Message 2 [ 2, 11730624 ] Message 3 [ 3, 14871246 ]

let i = 1;
const interval = setInterval(() => {
    console.log('Message ' + i + ' ', process.uptime());
    i++;
    if (i > 3) {
        clearInterval(interval);
    }
}, 1000);

Output

Message 1 1.094841971
Message 2 2.09636721
Message 3 3.098306832

@SeLub
Copy link
Author

SeLub commented Jun 15, 2024

process.nextTick() & process.uptime()

function preciseDelay(ms) {
    const start = process.uptime() * 1000; // convert to milliseconds
    return new Promise((resolve) => {
        function checkTime() {
            const now = process.uptime() * 1000; // convert to milliseconds
            const elapsed = now - start;
            if (elapsed >= ms) {
                resolve();
            } else {
                process.nextTick(checkTime);
            }
        }
        checkTime();
    });
}

for (let i = 1; i <= 3; i++) {
    await preciseDelay(1000);
    console.log('Message ' + i + ' ', process.uptime());

Output

Message 1 1.099711546
Message 2 2.106497274
Message 3 3.106818154

@SeLub
Copy link
Author

SeLub commented Jun 15, 2024

OpenAi: How we can make delay more precise?

To achieve a more precise delay in JavaScript, especially in environments like Node.js where setTimeout and setInterval may not always guarantee exact timing due to the event loop's nature, you can use process.hrtime() for high-resolution time measurements and combine it with a busy-wait loop (also known as spin-waiting or spinning) to achieve more precise timing. Here's how you can implement it:

function preciseDelay(ms) {
    const start = process.hrtime();
    const target = start[0] * 1000 + start[1] / 1e6 + ms;

    return new Promise((resolve) => {
        function spinWait() {
            const now = process.hrtime();
            const currentTime = now[0] * 1000 + now[1] / 1e6;

            if (currentTime >= target) {
                resolve();
            } else {
                setImmediate(spinWait);
            }
        }

        spinWait();
    });
}

for (let i = 1; i <= 3; i++) {
    await preciseDelay(1000);
    console.log('Message ' + i + ' ', process.uptime());
}

Output

Message 1 1.104189437
Message 2 2.110839667
Message 3 3.111090676

Explanation:

Using process.hrtime(): This provides a high-resolution timestamp as an array of [seconds, nanoseconds].

Calculating Target Time: start captures the current time using process.hrtime(), and target calculates the precise future time to resolve the promise based on the specified ms delay.

Spin-Wait Loop: Inside preciseDelay, spinWait checks the current time using process.hrtime() in a loop (setImmediate for Node.js environment), until the current time exceeds or meets the target time.

Resolution: Once the target time is reached, resolve() is called to complete the promise.

Benefits of this approach:

High Precision: Using process.hrtime() allows for high-resolution timing, which is crucial for precise measurements.
Minimizing Variability: By using a spin-wait loop with setImmediate, you reduce the variability introduced by the event loop, improving the precision of the delay.

Considerations:

CPU Usage: Spin-waiting can consume CPU cycles while waiting, so it's essential to balance precision with efficiency, depending on your application's needs.
Node.js Environment: This approach is suitable for Node.js environments where setImmediate is available. For browsers, requestAnimationFrame or Performance.now() might be used instead.
By combining process.hrtime() for precise time measurements and a spin-wait loop, you can achieve more accurate and reliable delays in your JavaScript applications.

@SeLub
Copy link
Author

SeLub commented Jun 25, 2024

const _ = require("underscore");

const startTime = process.hrtime();
console.log("startTime: ", startTime);

var log = _.bind(console.log, console);
_.delay(log, 2000, "1 " + process.uptime());
_.delay(log, 3000, "2 " + process.uptime());
_.delay(log, 4000, "3 " + process.uptime());

Output

startTime: [ 28842, 94505554 ]
1 0.113224137
2 0.11378397
3 0.113840184

@SeLub
Copy link
Author

SeLub commented Jul 22, 2024

function printNumbers() {
  setTimeout(function () {
    console.log("Message 1 ", process.uptime());
  }, 1000);

  setTimeout(function () {
    console.log("Message 2 ", process.uptime());
  }, 2000);

  setTimeout(function () {
    console.log("Message 3 ", process.uptime());
  }, 3000);
}

printNumbers();

Output

Message 1 1.103750838
Message 2 2.103497816
Message 3 3.103996886

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment