{"id":25916086,"url":"https://github.com/apollo79/timers","last_synced_at":"2026-05-10T11:49:27.442Z","repository":{"id":62595519,"uuid":"560897421","full_name":"apollo79/timers","owner":"apollo79","description":"All timing functions you need - long and async timeouts, intervals, promise timeouts and more","archived":false,"fork":false,"pushed_at":"2024-04-24T19:13:28.000Z","size":180,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-17T19:21:23.342Z","etag":null,"topics":["deno","interval","timeout","timer","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apollo79.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-11-02T14:05:44.000Z","updated_at":"2024-04-24T19:13:32.000Z","dependencies_parsed_at":"2023-01-25T11:45:41.713Z","dependency_job_id":null,"html_url":"https://github.com/apollo79/timers","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollo79%2Ftimers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollo79%2Ftimers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollo79%2Ftimers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apollo79%2Ftimers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apollo79","download_url":"https://codeload.github.com/apollo79/timers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":241661430,"owners_count":19998951,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["deno","interval","timeout","timer","typescript"],"created_at":"2025-03-03T12:19:11.082Z","updated_at":"2026-05-10T11:49:27.434Z","avatar_url":"https://github.com/apollo79.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# timers\n\nAll the timing functions you need - for Deno, Bun and the browser.\n\n[![MIT License](https://img.shields.io/badge/License-MIT-green.svg)](https://choosealicense.com/licenses/mit/)\n[![Deno](https://github.com/apollo79/timers/actions/workflows/deno.yml/badge.svg)](https://github.com/apollo79/timers/actions/workflows/deno.yml)\n[![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/apollo79/2d19c30060d11652aced4d805a104884/raw/timers-main-lcov-coverage.json)](https://github.com/apollo79/timers/actions/workflows/deno.yml)\n[![JSR version](https://jsr.io/badges/@apollo79/timers)](https://jsr.io/@apollo79/timers)\n[![JSR Score](https://jsr.io/badges/@apollo79/timers/score)](https://jsr.io/@apollo79/timers/score)\n\n## Installation\n\n### JSR\n\n#### deno\n\n```bash\ndeno add jsr:@apollo79/timers\n```\n\n#### npm (use any of npx, yarn dlx, pnpm dlx, or bunx)\n\n```bash\nnpx jsr add @apollo79/timers\n```\n\n## Features and usage\n\nAfter installing, just import the functions you need from `@apollo79/timers` /\n`jsr:@apollo79/timers`.\n\n### long timeouts and intervals\n\nWith every function `timers` exports, it is possible to have a timeout or\ninterval that is longer than 24.8 days (2^31-1 milliseconds).\n\nIf you need only this functionality, `timers` exports the functions\n`setTimeout`, `setInterval`, `clearTimeout` and `clearInterval`.\n\nThey are almost completely compatible with the Web API's functions, but it is\nnot allowed to pass a string as function argument to one of them.\n\n#### **Important Note**\n\n_You can't use the native functions mixed with the functions exported by this\nmodule! So, if you import `setTimeout`, you should import `clearTimeout` as\nwell, as the native function won't clear the timeout!_\n\n```ts\nconst timeout = setTimeout(() =\u003e {\n  console.log(\"in 30 days\");\n}, 1000 * 60 * 60 * 24 * 30);\n\nconst interval = setInterval(() =\u003e {\n  console.log(\"every 30 days\");\n}, 1000 * 60 * 60 * 24 * 30);\n\n// Clear them\nclearTimeout(timeout);\nclearInterval(interval);\n```\n\n#### **Tip**\n\nIf you don't want the native functions overwritten, `setTimeout` and\n`setInterval` are exported as `setLongTimeout` and `setLongInterval` as well.\nThis also applies to `clearTimeout` and `clearInterval`. Also you can at any\ntime use `globalThis.setTimeout`, which applies to the other functions as well\n\n```ts\nimport {\n  clearLongInterval,\n  clearLongTimeout,\n  setLongInterval,\n  setLongTimeout,\n} from \"@apollo79/timers\";\n```\n\n### time strings\n\nWith each function expect `setInterval` and `setTimeout`, that `timers` exports,\nit is possible to use a time string as delay argument instead of the number of\nmilliseconds. For example:\n\n```ts\nevery(\"1minute\").do(() =\u003e {\n  console.log(new Date().toLocaleTimeString());\n});\n```\n\n#### supported format\n\n- ms, millisecond, milliseconds\n- s, sec, secs, second, seconds\n- m, min, mins, minute, minutes\n- h, hour, hours\n- d, day, days\n\n##### Examples\n\n- `2 days, 5 hours and 2 minutes`\n- `3sec, 2ms`\n- `5mins3secs`\n\n### `delay`\n\n`timers` exports the function `delay`. The API is like the\n[delay function](https://deno.land/std/async/delay.ts) from deno's std library,\nbut it returns an `AbortablePromise`, so you can abort the promise with calling\n`abort()` on it. It has two options:\n\n- `signal`: An AbortSignal that aborts the timeout. The delay function will\n  reject.\n- `persistent` (only available in Deno): Indicates whether the process should\n  continue to run as long as the timer exists. This is `true` by default.\n\n```ts\nconst MSG = \"Please type your name\";\nconst info = document.querySelector(\"p.info\");\nconst nameInput = document.querySelector(\"input.name\");\nconst abort = new AbortController();\nconst { signal } = abort;\n\nnameInput.addEventListener(\"input\", () =\u003e abort.abort(), { once: true });\n\nawait delay(2000, {\n  signal,\n});\n\ninfo.textContent = MSG;\n```\n\n### `times`\n\nAnother function `timers` provides is `times`. It is basically like\n`setInterval`, but executes the interval just a certain number of times. Like\nwith `delay`, you have the `signal` and `persistent` (only available in Deno)\noptions, plus the `silent` (supresses errors in the callback) and the `args`\noption. Instead of passing the args as rest parameter, like with `setInterval`,\nyou must pass them as `array`, in order to have the other options.\n\n```ts\nconst paragraph = document.querySelector(\"p.numbers\");\nconst abortBtn = document.querySelector(\"button.abort\");\nconst abort = new AbortController();\nconst { signal } = abort;\n\nabortBtn.addEventListener(\"click\", () =\u003e abort.abort(), { once: true });\n\nlet i = 0;\ntimes(\n  () =\u003e {\n    paragraph.textContent += `${i}, `;\n\n    i++;\n  },\n  200,\n  20,\n  {\n    signal,\n  },\n);\n```\n\n### `every`\n\n`every` is syntactical sugar over an `Interval`. The function returns an `Every`\nclass instance. To start the interval, you call `do()` with your callback. To\nset how often the callback should get executed, call `limit()` on it, but only\n_before_ you call `do()`. Calling `stop()` aborts the interval. It supports the\nfollowing options:\n\n- `signal`\n- `persistent`\n- `args`\n- `silent`\n\n```ts\nevery(\"1min\").limit(60).do(() =\u003e {\n  console.log(new Date().toLocaleTimeString());\n});\n```\n\n### `after`\n\n`after` is like `every`, but for timeouts. It does, of course, not have the\n`limit` function, since it gets only executed once. The following options are\navailable:\n\n- `signal`\n- `persistent`\n- `args`\n- `silent`\n\n```ts\nafter(\"1min\").do(() =\u003e {\n  console.log(new Date().toLocaleTimeString());\n});\n```\n\n### `pTimeout`\n\nAdapted from [p-timeout](https://github.com/sindresorhus/p-timeout). Times out a\npromise after a specified amount of time.\n\n```ts\nconst delayedPromise = delay(500);\n\nawait pTimeout(delayedPromise, 50);\n\n// =\u003e [TimeoutError: Promise timed out after 50 milliseconds]\n```\n\nThe function expects at least two arguments:\n\n- `promise`: A `Promise` or a function returning a `Promise`\n- `delay`: The time in milliseconds after which the function rejects\n- `options` (not required):\n  - `signal`: An `AbortSignal` to abort the function even before it rejects\n  - `fallbackFn`: Do something other than rejecting with an error on timeout.\n    You could for example retry.\n  - `failMessage`: A custom error message. Default:\n    `'Promise timed out after 50 milliseconds'`\n  - `failError`: Specify a custom `Error`. It's recommended to sub-class of\n    `TimeoutError`.\n\nIt returns a decorated `Promise`, which can be aborted with its `abort()`\nmethod.\n\n#### Using with a function\n\nInstead of passing a `Promise` directly, you can pass a function that retuns a\n`Promise`:\n\n```ts\nconst pingApi = () =\u003e fetch(\"/api\");\n\nawait pTimeout(pingApi, \"50 ms\");\n```\n\nThe function can take an `AbortSignal` as parameter as well, which `abort` event\nfires, when the timeout times out:\n\n```ts\nconst pingApi = (signal) =\u003e fetch(\"/api\", { signal });\n\nawait pTimeout(pingApi, 50);\n```\n\n`pTimeout` also passes down the signal it got:\n\n```ts\nconst abort = new AbortController();\nconst { signal } = abort;\n\nconst pingApi = (signal) =\u003e fetch(\"/api\", { signal });\n\npTimeout(pingApi, \"100milliseconds\", { signal });\n\ndelay(50).then(() =\u003e abort.abort());\n```\n\n### `timeout` and `interval`\n\n`timeout` and `interval` are like `setTimeout` and `setInterval`, but are typed,\nsupport `time strings` meaning that the `args` option's type must equal the type\nof the argument expected by the callback. and supports these options:\n\n- `signal`\n- `persistent` (only available in Deno)\n- `args`\n- `times` (only `interval`)\n\n```ts\nconst timeout = timeout(() =\u003e {\n  console.log(\"in 30 days\");\n}, \"30 days\");\n\nconst interval = setInterval(() =\u003e {\n  console.log(\"every 30 days\");\n}, \"30 days\");\n\n// Clear them\nclearTimeout(timeout);\nclearInterval(interval);\n```\n\n### `Timeout` and `Interval` classes\n\nUnder the hood, all of the functions listed above use the `Timeout` and\n`Interval` classes.\\\nThey are exported as well and you can use them to create timeouts without\\\nrunning them directly.\n\n```ts\nconst notifyBtn = document.querySelector(\"button.notify\");\nconst timeout = new Timeout(() =\u003e {\n  console.log(\"hello world\");\n}, 1000);\n\n// WARNING: running a timeout two times will throw an error\nnotifyBtn.addEventListener(\"click\", () =\u003e timeout.run(), { once: true });\n```\n\nFor `Timeout`, the following options are available:\n\n- `signal`\n- `persistent` (only available in Deno)\n- `silent`\n- `args`\n- `times` (only for `Interval`)\n\n#### Properties\n\n- `id`: The Id of the timer, can be used with `clearTimeout` and `clearInterval`\n- `aborted`: A Promise, that resolves, when the timer gets aborted, but only, if\n  the abort happens with a call of the `abort` method or the abortion via an\n  `AbortController`.\n- `isAborted`: A boolean indicating whether the timer has been aborted\n- `persistent` (only available in Deno): A boolean indicating whether the\n  process should continues running as long as the timer exists. This is `true`\n  by default.\n- _deprecated_: `timer`: The Id of the timer. Use `id` instead.\n- `ran`: A boolean indicating whether the timer ran already. Gets only set to\n  `true` on `Interval` when the `times` option has been passed and the interval\n  has run `times` times.\n- `running`: A boolean indicating whether the timeout is currently running\n\n##### Only `Interval`\n\n- `runs`: A number representing the amount of times the interval has run until\n  now\n\n#### Methods\n\n- `run()`: runs the timeout and returns the timeout's id\n- `abort(reason?: any)`: aborts the timeout\n- `unref()`: makes the process not continue to run as long as the timer exists\n  (only working in Deno)\n- `ref()`: makes the process continue to run as long as the timer exists (only\n  working in Deno)\n\n##### **NOTE**\n\n_It is not possible to use Deno.unrefTimer() or Deno.refTimer() directly with\nthe id returned by setInterval or setTimeout_\n\n## Running Tests\n\nTo run tests, clone the repository, and run the following command\n\n```bash\ndeno task test\n```\n\n## Contributing\n\nContributions are always welcome!\n\nYou found a bug or have an idea about a function, that is not yet implemented in\nthis module?\\\nFeel free to open an [issue](https://github.com/apollo79/timers/issues/new) or a\nPR!\n\n## License\n\n[MIT](https://choosealicense.com/licenses/mit/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapollo79%2Ftimers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapollo79%2Ftimers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapollo79%2Ftimers/lists"}