これは、なにをしたくて書いたもの?
Node.js v15からPromise
版のsetTimeout
、setInterval
が導入されているのですが、どこのモジュールなのかよく忘れるのでメモ。
Timers Promises API
Promise
版のsetTimeout
、setInterval
(とsetImmediate
)は、timersモジュールに含まれています。
Timers | Node.js v18.15.0 Documentation
こちらですね。
Node.js v15で導入され、v16で実験的モジュールの位置づけを脱した、と書かれています。
これらの関数では、これまでのsetTimeout
、setInterval
、setImmediate
とは異なり、Promise
を返すようになっています。
軽く試しておきましょう。
環境
今回の環境は、こちら。
$ node --version v18.15.0 $ npm --version 9.5.0
準備
確認は、TypeScriptで行うことにします。
$ npm init -y $ npm i -D typescript $ npm i -D @types/node@v18 $ npm i -D prettier $ mkdir src
依存関係。
"devDependencies": { "@types/node": "^18.15.0", "prettier": "^2.8.4", "typescript": "^4.9.5" }
scripts
。
"scripts": { "build": "tsc --project .", "build:watch": "tsc --project . --watch", "format": "prettier --write src" },
設定ファイル。
tsconfig.json
{ "compilerOptions": { "target": "esnext", "module": "commonjs", "moduleResolution": "node", "lib": ["esnext"], "baseUrl": "./src", "outDir": "dist", "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "noImplicitOverride": true, "noImplicitReturns": true, "noPropertyAccessFromIndexSignature": true, "esModuleInterop": true }, "include": [ "src" ] }
.prettierrc.json
{ "singleQuote": true, "printWidth": 120 }
setTimeout
まずはsetTimeout
から。
src/set-timeout.ts
import { setTimeout } from 'node:timers/promises'; async function setTimeoutTest(): Promise<void> { console.log(`[${new Date().toISOString()}] start`); await setTimeout(2 * 1000); console.log(`[${new Date().toISOString()}] end`); } setTimeoutTest();
こんな感じで、setTimeout
関数の戻り値がPromise
になっているのでasync
/await
と組み合わせて使えます。
await setTimeout(2 * 1000);
確認。
$ npm run build $ node dist/set-timeout.js [2023-03-12T14:51:32.292Z] start [2023-03-12T14:51:34.296Z] end
指定時間、停止しているのが確認できます。
src/set-timeout-with-return-value.ts
import { setTimeout } from 'node:timers/promises'; async function setTimeoutWithReturnTest(): Promise<void> { console.log(`[${new Date().toISOString()}] start`); const value = await setTimeout(2 * 1000, 'return value'); console.log(`[${new Date().toISOString()}] end, value = ${value}`); } setTimeoutWithReturnTest();
また、第2引数を指定すると、戻り値のPromise
に含める値を指定できます。
const value = await setTimeout(2 * 1000, 'return value');
確認。
$ npm run build $ node dist/set-timeout-with-return-value.js [2023-03-12T14:53:46.062Z] start [2023-03-12T14:53:48.068Z] end, value = return value
setInterval
続いて、setInterval
。
src/set-interval.ts
import {setInterval } from 'node:timers/promises'; async function setIntervalTest(): Promise<void> { for await (const _ of setInterval(1 * 1000)) { console.log(`[${new Date().toISOString()}] print...`) } } setIntervalTest();
1秒おきに繰り返すようにしています。
for await (const _ of setInterval(1 * 1000)) { console.log(`[${new Date().toISOString()}] print...`) }
確認。
$ npm run build $ node dist/set-interval.js [2023-03-12T15:11:53.096Z] print... [2023-03-12T15:11:54.097Z] print... [2023-03-12T15:11:55.099Z] print... [2023-03-12T15:11:56.099Z] print... [2023-03-12T15:11:57.101Z] print... [2023-03-12T15:11:58.102Z] print... [2023-03-12T15:11:59.103Z] print... [2023-03-12T15:12:00.105Z] print... [2023-03-12T15:12:01.105Z] print... [2023-03-12T15:12:02.106Z] print... [2023-03-12T15:12:03.107Z] print...
setInterval
もPromise
の戻り値を指定することができます。各繰り返しで返される値になります。
src/set-interval-with-return-value.ts
import {setInterval } from 'node:timers/promises'; async function setIntervalTest(): Promise<void> { for await (const startTime of setInterval(1 * 1000, Date.now())) { const now = Date.now(); console.log(`[${new Date().toISOString()}] startTime = ${new Date(startTime).toISOString()}`) if ((now - startTime) > 10000) { console.log(`[${new Date().toISOString()}] break`) break; } } } setIntervalTest();
10秒経過したら打ち切るように作成。
for await (const startTime of setInterval(1 * 1000, Date.now())) { const now = Date.now(); console.log(`[${new Date().toISOString()}] startTime = ${new Date(startTime).toISOString()}`) if ((now - startTime) > 10000) { console.log(`[${new Date().toISOString()}] break`) break; } }
確認。
$ npm run build $ node dist/set-interval-with-return-value.js [2023-03-12T15:14:10.059Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:11.060Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:12.061Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:13.062Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:14.063Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:15.065Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:16.065Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:17.066Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:18.067Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:19.068Z] startTime = 2023-03-12T15:14:09.057Z [2023-03-12T15:14:19.069Z] break
その他
今回、setTimeout
、setInterval
の第2引数までを使いましたが、第3引数にオプションを指定できます。
ref
… 残っている処理がタイマーのみとなっている場合、Node.jsのイベントループを終了する場合はfalse
。デフォルトはtrue
signal
… タイマー処理をキャンセルするためのAbortSignal
を指定
キャンセルについては、こちらに記載があります。
AbortController
と一緒に使うようです。
こちらについては、この記載のみで。
まとめ
Promise
版のsetTimeout
、setInterval
を試してみました。
よくどこのモジュールだったか忘れるので…メモとして残しておきます。