What do you think about such an object function?

const stc = {
  delayTimer: {},
  sleep: (m, name) => new Promise(r => stc.delayTimer[name] = setTimeout(r, m)),
  sleepProlong: async (ms, name)=> {
    if (stc.delayTimer[name])
    delete stc.delayTimer[name];
    return await stc.sleep(ms, name);

It is used to make a delay, but additionally when you call it again before the set time expires, it clears the counter and counts from the beginning, does not release the function any further.

async function s (){
  await stc.sleepProlong(5000, "mek"); 

For example, when in the console you will start s() before 5 seconds elapses from the previous firing, "we" will not appear. when you stop, it will complete the last counting and "we" will be displayed.

What do you think? Can you do it better?


What is it for?

Without knowing what you would use this for I can only go by your question.

The behaviour of stc is not what the question's title suggests as it is very easy to make it fail or behave in a non intuitive manner.

Forever pending

Consider the following use example

stc.sleep(1000, "test").then(()=>log("Test timeout");  // this promise is never resolved
        stc.sleepProlong(2000, "test").this(()=>log("Test prolonged timeout")

The first promise is left pending and will never be resolved.

Some other potential problems

  • Each time sleepProlong is called you leave another promise unresolved.
  • When sleepProlong is called the name implies that it "prolongs sleep", but if the sleep has already timeouted out it creates a new sleep???
  • If sleep is called with the same name as an existing sleep, the previous sleep can no longer be prolonged,
  • The stc interface exposes delayTimer making the state of stc untrustable.


From the question's title I would expect

  • that there is only one promise for a named sleep.
  • that the sleep and prolonged sleep can be canceled
  • that the sleep can be prolonged indefinitely
  • that attempting to prolong a sleep that has timeout does nothing.
  • that calling sleep with the name of an unresolved existing sleep does nothing

Some general style and coding points

  1. Function argument names are inconsistent you call the timeout delay m in one function and ms in the other.
  2. The line delete stc.delayTimer[name]; is not needed as you overwrite the value by calling sleep on the next line.
  3. not using curlies {} to delimited statement blocks is a bad habit, Always delimit statement blocks with {...}.You had if (stc.delayTimer[name]) clearTimeout(stc.delayTimer[name]); is better as if (stc.delayTimer[name]) { clearTimeout(stc.delayTimer[name]); }
  4. There is no need to check if the named timeout event handle exists. clearTimeout will ignore undefined and already timed out handles. Thus if (stc.delayTimer[name]) { clearTimeout(stc.delayTimer[name]); } can be clearTimeout(stc.delayTimer[name]); and not change the behaviour.
  5. This may just be my personal preference but it feels wrong having the time m, or ms as the first argument. Putting the name first and then the delay seems more natural (and thus easier to remember)
  6. You don't need to await the promise you return in the async function, Async functions do this automatically .
  7. Ensure that you protect important state variables. If entries in the object delayTimer are mutated then you lose the ability to maintain stc's correct behaviour. You can protect it via closure.

Cleanup and keeping original behaviour

without changing the behaviour of you code I have made changes as outlined in the above points, and modified some names.

const stc = (() => {
    const handles = {};
    return {
        sleep(name, time) { return new Promise(r => handles[name] = setTimeout(r, time)) },
        async prolong(name, time) {
            return stc.sleep(name, time);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.