Etherealm
Etherealm

Reputation: 2484

How to execute setTimeout function immediately after the delay?

I want to execute setTimeout after the delay and not wait for it to be called from the message queue after all the other functions have executed. Please refer the code below:

let test = function(){ console.log('test') }
setTimeout(() => console.log('hi'), 2000)

test();
test();
test();
.
.
.
.
this code takes more than 2 seconds to execute;

How to get setTimeout after 2 seconds instead of at the end ?

Upvotes: 3

Views: 1405

Answers (3)

abadalyan
abadalyan

Reputation: 1235

I thought I would mention that if those test() calls do not perform DOM operations you could possibly move them to a worker.

Web Workers allow running code on a background thread that doesn't block your main UI thread. I've created a quick example that runs a synchronous task of arbitrary duration on a worker thread. On the main thread setInterval and setTimeout calls are running uninterrupted.

See it in action.

index.js

let interval = setInterval(() => console.log("Not blocked"), 500);

console.log("Scheduling to run in 2 seconds");
setTimeout(() => {
  console.log("2 seconds passed. Running scheduled task! ");
}, 2000);

let longTaskRunner = new Worker("./src/worker.js");
let taskDuration = 3;
console.log(
  `Starting synchronous task that takes more than ${taskDuration} seconds`
);

longTaskRunner.postMessage(taskDuration);
longTaskRunner.onmessage = function(e) {
  console.log(`Long task completed in ${e.data} seconds`);
  clearInterval(interval);
};
longTaskRunner.onerror = function(e) {
  console.log(e.message);
};

worker.js

self.onmessage = function(e) {
  const runFor = e.data * 1000;
  let startedAt = Date.now();
  let timeElapsed = 0;

  while (timeElapsed < runFor) {
    timeElapsed = Date.now() - startedAt;
  }

  self.postMessage(timeElapsed / 1000);
};

Upvotes: 1

CertainPerformance
CertainPerformance

Reputation: 370729

If the chain of tests is consuming more than 2000ms of CPU time synchronously ("blocking"), I don't think it's possible like that - the best you could do is check in test (or in a function wrapped around it) whether the time difference between the start (where your setTimeout is currently) and the current time is more than 2 seconds - if so, execute the function. For example:

console.log('start');
let hasRun = false;
const fnToRunLater = () => console.log('hi');
const startTime = Date.now();
function test() {
  const now = Date.now();
  if (!hasRun && now - startTime > 2000) {
    fnToRunLater();
    hasRun = true;
  }
  for (let i = 0; i < 2e8; i++) {
    // some expensive operations
  }
}
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
if (!hasRun) {
  fnToRunLater();
}
console.log('done');

(warning: below snippet containing the code above will block your browser for a bit, depending on your hardware)

// look at the timing in your browser console, not the snippet console

console.log('start');
let hasRun = false;
const fnToRunLater = () => console.log('hi');
const startTime = Date.now();
function test() {
  const now = Date.now();
  if (!hasRun && now - startTime > 2000) {
    fnToRunLater();
    hasRun = true;
  }
  for (let i = 0; i < 2e8; i++) {
    // some expensive operations
  }
}
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
test();
if (!hasRun) {
  fnToRunLater();
}
console.log('done');

If an individual test takes too long, and the timeout isn't accurate enough (eg, if a test takes 400ms and this takes the difference from 1800ms to 2200ms, and that 200ms of inaccuracy is too much), then you'll have to change the test code so that it does multiple checks inside.

Upvotes: 0

brk
brk

Reputation: 50291

You may not need setTimeout. Instead return a promise from test function and do rest of the things inside then which will only work once test is resolved

let test = function() {
  return new Promise(function(resolve, reject) {
    console.log('test');
    resolve('test executed')
  })
}


test().then(function(data) {
  console.log(data)
});

Upvotes: 1

Related Questions