Delay a promise a specified amount of time

Related tags

Control Flow delay
Overview

delay

Delay a promise a specified amount of time

If you target Node.js 15 or later, you can do await require('timers/promises').setTimeout(1000) instead.

Install

$ npm install delay

Usage

const delay = require('delay');

(async () => {
	bar();

	await delay(100);

	// Executed 100 milliseconds later
	baz();
})();

API

delay(milliseconds, options?)

Create a promise which resolves after the specified milliseconds.

delay.reject(milliseconds, options?)

Create a promise which rejects after the specified milliseconds.

delay.range(minimum, maximum, options?)

Create a promise which resolves after a random amount of milliseconds between minimum and maximum has passed.

Useful for tests and web scraping since they can have unpredictable performance. For example, if you have a test that asserts a method should not take longer than a certain amount of time, and then run it on a CI, it could take longer. So with .range(), you could give it a threshold instead.

milliseconds

mininum

maximum

Type: number

Milliseconds to delay the promise.

options

Type: object

value

Type: unknown

Optional value to resolve or reject in the returned promise.

signal

Type: AbortSignal

The returned promise will be rejected with an AbortError if the signal is aborted. AbortSignal is available in all modern browsers and there is a ponyfill for Node.js.

delayPromise.clear()

Clears the delay and settles the promise.

delay.createWithTimers({clearTimeout, setTimeout})

Creates a new delay instance using the provided functions for clearing and setting timeouts. Useful if you're about to stub timers globally, but you still want to use delay to manage your tests.

Advanced usage

Passing a value:

const delay = require('delay');

(async() => {
	const result = await delay(100, {value: '🦄'});

	// Executed after 100 milliseconds
	console.log(result);
	//=> '🦄'
})();

Using delay.reject(), which optionally accepts a value and rejects it ms later:

const delay = require('delay');

(async () => {
	try {
		await delay.reject(100, {value: new Error('🦄')});

		console.log('This is never executed');
	} catch (error) {
		// 100 milliseconds later
		console.log(error);
		//=> [Error: 🦄]
	}
})();

You can settle the delay early by calling .clear():

const delay = require('delay');

(async () => {
	const delayedPromise = delay(1000, {value: 'Done'});

	setTimeout(() => {
		delayedPromise.clear();
	}, 500);

	// 500 milliseconds later
	console.log(await delayedPromise);
	//=> 'Done'
})();

You can abort the delay with an AbortSignal:

const delay = require('delay');

(async () => {
	const abortController = new AbortController();

	setTimeout(() => {
		abortController.abort();
	}, 500);

	try {
		await delay(1000, {signal: abortController.signal});
	} catch (error) {
		// 500 milliseconds later
		console.log(error.name)
		//=> 'AbortError'
	}
})();

Create a new instance that is unaffected by libraries such as lolex:

const delay = require('delay');

const customDelay = delay.createWithTimers({clearTimeout, setTimeout});

(async() => {
	const result = await customDelay(100, {value: '🦄'});

	// Executed after 100 milliseconds
	console.log(result);
	//=> '🦄'
})();

Related

  • delay-cli - CLI for this module
  • p-cancelable - Create a promise that can be canceled
  • p-min-delay - Delay a promise a minimum amount of time
  • p-immediate - Returns a promise resolved in the next event loop - think setImmediate()
  • p-timeout - Timeout a promise after a specified amount of time
  • More…
Comments
  • Add `.cancel()`

    Add `.cancel()`

    As suggested in #15.

    Notes:

    1. This depends on #16.
    2. Currently, abort() throws an AbortError. Perhaps that behavior should be optional? I usually find myself wanting to cancel everything that follows, and I'd rather not add a catch in those cases.
    3. I'm introducing a dependency on p-defer, which is lightweight, but still relevant.
    4. I'm not entirely sure which issue the unhandled rejection handler originally solved, so the PR probably introduces an issue with that. I'm not getting any warnings from the tests though. Is it the known failure in the tests?
    opened by timdp 18
  • delay.reject()

    delay.reject()

    Idea from: https://github.com/ariporad/ava/blob/c7b0154f8ae181e892d58ab1d50aee6154a9a743/test/test.js#L7-L12

    delay.reject(100, 'message');
    delay.reject(100, new Error('message')); // equivalent to the above
    

    If a string, it's converted to an Error, otherwise passed through.

    I know the first case is not like Promise.reject(), but is there any good reason not to reject with an error?

    @ariporad @jamestalmage Do you think it would be useful to have this here?

    enhancement help wanted question 
    opened by sindresorhus 17
  • Typescript dom reference causes failure in non-DOM contexts

    Typescript dom reference causes failure in non-DOM contexts

    The lib reference to dom https://github.com/sindresorhus/delay/blob/34e50092c96d05f3d248130212a163a22570618f/index.d.ts#L1 prevents this from being properly usable within non-DOM contexts such as react-native.

    node_modules/typescript/lib/lib.dom.d.ts:17604:6 - error TS2300: Duplicate identifier 'RequestInfo'.
    
    17604 type RequestInfo = Request | string;
               ~~~~~~~~~~~
    
    node_modules/@types/react-native/globals.d.ts:92:14
    92 declare type RequestInfo = Request | string;
                    ~~~~~~~~~~~
    RequestInfo' was also declared here.
    
    opened by ckknight 10
  • Remove thunk API

    Remove thunk API

    I know I modified the code a fair bit from the original. If you'd prefer I keep closer to the original code (e.g. variable names, use of p-defer, remove package-lock.json) then I will do that. I can also add any additional tests you have on your mind.

    opened by olsonpm 10
  • Fix tests and make code simpler/clearer

    Fix tests and make code simpler/clearer

    These commits avoid intermediary functions, shorten the code and deobfuscate the resolve/reject part of the code.

    I'm not sure of how you feel about retouching code that works, but I thought I'd make a PR to possibly improve readability of the code.

    opened by fregante 9
  • Add support for passing `AbortSignal` and move the `value` argument into options

    Add support for passing `AbortSignal` and move the `value` argument into options

    This adds support for aborting a delay through the native AbortSignal.

    This allows writing functions with async/await where the signal can just be passed down through functions without much boilerplate (in opposite to cancellable Promises). It is the cancellation mechanism used by modern APIs like fetch and WebAuthentication.

    Example use:

    async function pollStatus(signal) {
    	while (true) {
    		const status = await fetchStatus(signal)
    		if (status === 'pending') {
    			await delay(1000, signal)
     			continue
    		}
    		return status
    	}
    }
    async function fetchStatus(signal) {
    	const resp = await fetch('/api/status', { signal })
    	checkStatus(resp)
    	return await resp.json()
    }
    

    When the AbortSignal is aborted, it rejects with an AbortError like fetch does. This is so calling code does not continue execution and gets a chance to clean up resources in finally blocks. At the top level the error can be checked with err.name === 'AbortError'.

    I chose to allow passing AbortSignal as a second parameter too, which technically prevents users from using an AbortSignal as a resolve value, but I think the chance that someone wants to do that intentionally is basically zero. It would be possible to require delay(1000, null, signal) instead, but that would probably more bugs than the alternative.

    opened by felixfbecker 8
  • Factory method to create delay implementation with bound timer methods

    Factory method to create delay implementation with bound timer methods

    It'd be useful if I could do the following:

    import { factory } from 'delay'
    
    const delay = factory({ setTimeout, clearTimeout })
    

    Since this binds the implementation to the timer methods I've provided, I can then safely stub the timers using say lolex and still use the delay interface.

    enhancement help wanted 
    opened by novemberborn 7
  • Problems using

    Problems using

    I've been using the delay module in a typescript module (@google-cloud/profiler).

    I'd previously used the type definitions from DefinitelyTyped, so @types/delay, without issue. But when I try to use version 3.1.0 of this module (and use the types from this latest version), my module no longer compiles, and I get errors like:

    ts/test/test-time-profiler.ts:65:16 - error TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'typeof import("/usr/local/google/home/nolanmar/cloud-profiler-nodejs-working/cloud-profiler-nodejs/node_modules/delay/index")' has no compatible call signatures.
    
    65          await delay(2 * durationMillis);
                      ~~~~~~~~~~~~~~~~~~~~~~~~~
    

    Is this expected? Any advice for how I can migrate to version 3.1.0 of `delay?

    opened by nolanmar511 6
  • [WIP] Refactor the options interface

    [WIP] Refactor the options interface

    I came across this solution in this thread. It's more experimental and maybe we can take some ideas from it.

    However, it's not 100% identical to what we had. Because when using .reject(), the value is optional, which doesn't look like I can do easily with this approach.

    A second approach could be to just do this

    export interface Options {
    	signal?: AbortSignal,
    }
    
    export interface ValueOptions<Value> {
    	value: Value
    }
    
    declare const delay: {
    	(milliseconds: number, options?: Options): ClearablePromise<void>;
    
    	<Value>(milliseconds: number, options?: Options & ValueOptions<Value>): ClearablePromise<Value>;
    
    	reject(milliseconds: number, options?: Options & Partial<ValueOptions<Value>>): ClearablePromise<never>;
    };
    

    Wrapping it in Partial makes all the properties of that interface optional.

    I would be fine with keeping it as is though. Just wanted to share my ideas.

    opened by SamVerschueren 5
  • Slight (breaking) change to the API

    Slight (breaking) change to the API

    Since this thing is only 9 hours old, I think we're safe doing it.

    When used in this fashion:

    promiseFn()
      .then(delay(200))
    

    I think it should delay 200ms from the time the first promise resolves.

    opened by jamestalmage 5
  • Fix missing `range()` in `createWithTimers()` return value & require Node.js 10

    Fix missing `range()` in `createWithTimers()` return value & require Node.js 10

    This started with a simple bugfix:

    • DRY delay creation
    • Add test for range() and createWithTimers()

    Except that Node.js 6 doesn't do object spread. So I've changed this to require Node.js 10.

    Which requires a breaking change, so I've removed the default export.


    I'd appreciate this if this can ship without also upgrading to use ESM.

    opened by novemberborn 4
  • Delaying for more than ~24.8 days causes TimeoutOverflowWarning and immediate promise resolution

    Delaying for more than ~24.8 days causes TimeoutOverflowWarning and immediate promise resolution

    The default implementation of setTimeout can only accept values within the range of positive signed 32-bit integers. Passing a timeout greater than (2^31)-1 milliseconds (0x7FFFFFFF) yields a TimeoutOverflowWarning and causes the runtime to ignore the specified timeout, assuming a value of 1ms (which by the way seems a dangerous default, I would have opted for using the maximum supported value or straight out throw an error).

    This unexpected behavior is not documented in the README, but rather than documenting this quirk of the runtime I'd like to propose a solution: instead of relying on the bare setTimeout, delay could use a wrapped version of it. Something like this:

    const maxSupportedTimeout = 0x7fffffff;
    type TimeoutContext = { id: ReturnType<typeof setTimeout> };
    const defaultSetTimeout = (
      callback: (...args: any[]) => void,
      ms: number,
      timeoutContext?: Partial<TimeoutContext>
    ): TimeoutContext => {
      timeoutContext = timeoutContext || { id: undefined };
      if (ms > maxSupportedTimeout) {
        timeoutContext.id = setTimeout(
          defaultSetTimeout,
          maxSupportedTimeout,
          callback,
          ms - maxSupportedTimeout,
          timeoutContext
        );
      } else {
        timeoutContext.id = setTimeout(callback, ms);
      }
      return timeoutContext as TimeoutContext;
    };
    const defaultClearTimeout = (timeoutContext: TimeoutContext) =>
      clearTimeout(timeoutContext.id);
    

    The timeoutContext is passed by reference, therefore each time defaultSetTimeout gets called the timeout id gets updated, so that defaultClearTimeout can always access the most recent value.

    enhancement help wanted 
    opened by cdellacqua 5
Releases(v5.0.0)
  • v5.0.0(Feb 1, 2021)

    Breaking

    • Require Node.js 10 (#55) f3c7542

    Improvements

    • Fix missing range() in createWithTimers() return value (#55) f3c7542

    https://github.com/sindresorhus/delay/compare/v4.4.1...v5.0.0

    Source code(tar.gz)
    Source code(zip)
  • v4.4.1(Jan 30, 2021)

  • v4.4.0(Jul 18, 2020)

  • v4.3.0(Jun 12, 2019)

    Enhancements:

    • Allow sinon.useFakeTimers() to modify setTimeout() and clearTimeout() (used by delay) after delay loads (#45) 1316fd7

    https://github.com/sindresorhus/delay/compare/v4.2.0...v4.3.0

    Source code(tar.gz)
    Source code(zip)
  • v4.2.0(Apr 8, 2019)

  • v4.1.0(Oct 10, 2018)

    • Add delay.createWithTimers() method. https://github.com/sindresorhus/delay/commit/e589469fe9d86696a606b0c7cb888f999b9aea91
    • Fix TypeScript type definition conflict with React Native. https://github.com/sindresorhus/delay/commit/04ef16fdeeb6b2487f0985eeb1089b4ee58f5761

    https://github.com/sindresorhus/delay/compare/v4.0.1...v4.1.0

    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Sep 3, 2018)

Owner
Sindre Sorhus
Full-Time Open-Sourcerer. Wants more empathy & kindness in open source. Focuses on Swift & JavaScript. Makes macOS apps, CLI tools, npm packages. Likes unicorns
Sindre Sorhus
:bird: :zap: Bluebird is a full featured promise library with unmatched performance.

Got a question? Join us on stackoverflow, the mailing list or chat on IRC Introduction Bluebird is a fully featured promise library with focus on inno

Petka Antonov 20.2k Jan 5, 2023
:bird: :zap: Bluebird is a full featured promise library with unmatched performance.

Got a question? Join us on stackoverflow, the mailing list or chat on IRC Introduction Bluebird is a fully featured promise library with focus on inno

Petka Antonov 20.2k Dec 31, 2022
Promise ponyfill with pinkie

pinkie-promise ES2015 Promise ponyfill Module exports global Promise object (if available) or pinkie Promise polyfill. Install $ npm install --save pi

Vsevolod Strukchinsky 120 Jan 16, 2022
Memoize promise-returning functions. Includes cache expire and prefetch.

promise-memoize Memoize promise-returning functions. Includes cache expire and prefetch. When data expire mode enabled, new values are fetched in adva

Nodeca 56 Nov 1, 2022
Awesome Observable related stuff - An Observable is a collection that arrives over time.

Awesome Observables An Observable is a collection that arrives over time. Observables can be used to model push-based data sources such as events, tim

Sindre Sorhus 320 Dec 17, 2022
Notifies and then closes draft pull requests that have had no activity for a specified amount of time.

Close Stale Draft Pull Requests This action has been inspired by microsoft/vscode-github-triage-actions, actions/stale and probot/stale, ultimately wr

Multi Theft Auto 2 Jan 7, 2022
Work around some mobile browser's 300ms delay on the click event.

jQuery fastClick plugin Work around the 300ms delay for the click event in some mobile browsers (e.g. Android and iOS). Code based on http://code.goog

Dave Hulbert 132 Jul 6, 2020
Inside-out promise; lets you call resolve and reject from outside the Promise constructor function.

Inside-out promise; lets you call resolve and reject from outside the Promise constructor function.

Lily Scott 3 Feb 28, 2022
Adds promise support (rejects(), doesNotReject()) to tape by decorating it using tape-promise.

Tape With Promises Adds promise support (rejects(), doesNotReject()) to tape by decorating it using tape-promise. Install npm install --save-dev @smal

Small Technology Foundation 3 Mar 21, 2022
An alarm clock is a clock that is designed to alert an individual or group of individuals at a specified time.

An alarm clock (or sometimes just an alarm) is a clock that is designed to alert an individual or group of individuals at a specified time. The primary function of these clocks is to awaken people from their night's sleep or short naps; they are sometimes used for other reminders as well.

Anupam Moharana 1 Dec 25, 2021
project overview tool, used to analyze the amount of code, the number of files, code statistics and so on.

pot z-pot is a project overview tool, used to analyze the amount of code, the number of files, code statistics and so on. 项目概述工具,用于分析代码量、文件数、代码统计等。 快速

zhangchi 18 Aug 10, 2022
Generate a big amount of tests

Generate a big amount of tests This repo was created for jest learning purposes. It aims to generate a big amount of tests (based in a template) to ve

Ricardo Montuan 2 Feb 17, 2022
A fast and optimized middleware server with an absurdly small amount of code (300 lines) built on top of Deno's native HTTP APIs

A fast and optimized middleware server with an absurdly small amount of code (300 lines) built on top of Deno's native HTTP APIs with no dependencies. It also has a collection of useful middlewares: log file, serve static, CORS, session, rate limit, token, body parsers, redirect, proxy and handle upload. In "README" there are examples of all the resources. Faster's ideology is: all you need is an optimized middleware manager, all other functionality is middleware.

Henrique Emanoel Viana 19 Dec 28, 2022
Minimize the amount of walls necessary by graph theory!

minCutWall Minimize the amount of walls necessary by graph theory! I've tried my best to make the code as easy as possible to understand. Feel free to

Josef Wittmann 5 Oct 29, 2022
Jonathan Parker 6 Nov 23, 2022
A simple Node.js package that helps you not to look up JavaScript promise syntax every time you use it.

A simple Node.js package that helps you not to look up JavaScript promise syntax every time you use it. Simple: Provides abstraction of the promise sy

Saad Irfan ⚡️ 9 Oct 8, 2022
Sanitize untrusted HTML (to prevent XSS) with a configuration specified by a Whitelist

Sanitize untrusted HTML (to prevent XSS) with a configuration specified by a Whitelist. xss is a module used to filter input from users to prevent XSS

老雷 4.8k Jan 2, 2023
⌨️ A tiny library for creating a typing effect on specified text element.

⌨️ TinyTyper - a tiny library for creating a typing effect on specified text element. Demo Size (It's really tiny) Minimized: 2.9KB Gziped: 1.1KB Inst

Korney Vasilchenko 175 Sep 29, 2021
An interpreter for College Board's specified pseudocode for the AP Computer Science Principles Exam.

College Board Pseudocode Interpreter A playground for this interpreter is up on my website. This project is a mostly-functioning interpreter for Colle

Daniel 7 Nov 16, 2022