2021/04/20にリリースされたNode.js v16の主な変更点を紹介します。
- M1 MacでもNode.jsが使えるようになります
- V8 v9.0
- Timers Promises APIが安定版になりました
- fs.rmdirのrecursiveオプションがDeprecatedになりました
- Node.js v15の機能がLTSとして使えるようになる
- 最後に
- 参考記事
- 変更履歴
M1 MacでもNode.jsが使えるようになります
Node.js v16.0.0は、Apple Silicon、いわゆるM1チップと呼ばれるAppleの新しいチップに対応したNode.jsの実行ファイルが公式で配布される最初のバージョンになります。
v15.xでもソースコードからのビルドでM1 MacでもNode.jsは使えていました。nvmなどインストールして使えていたのもソースコードからビルドしていたからです。
インストーラーの.pkgファイルにはIntel用(darwin-x64)とARM用(darwin-arm64)が両方サポートされています。
なので、以下の公式ダウンロードページからmacOS Installer
をクリックしてnode-v16.0.0.pkgをクリックするだけでインストールできます。
.tar.gz形式は別々で配布されています。以下のページからそれぞれダウンロードできます。
V8 v9.0
JavaScriptエンジンV8が新しくなりました。
Node.js v15はV8 8.6でしたので、V8 8.7〜9.0までに追加された機能はNode.js v16以降で使うことができます。
詳細なV8の変更点については公式ブログをご確認ください。
この記事ではJavaScriptに関する内容を紹介します。
Atomics.waitAsync
Atomics.waitAsync
はV8 8.7で追加されました。
まず、Atomics.wait
というAPIの説明をします。
このAPIはInt32Array
またはBigInt64Array
の指定された位置に指定された値が格納されるまでスレッドがスリープする機能です。Int32Array
やBigInt64Array
がSharedArrayBuffer
を使ってスレッド間で共有されているときのみ使えます。
const sab = new SharedArrayBuffer(1024); const int32 = new Int32Array(sab); Atomics.wait(int32, 0, 0); // この間に別スレッドなどで変数int32の0番目の値が書き換えられるまで待つ // 別スレッドで書き換えられた値を表示する console.log(int32[0]); // 100
// 別スレッドでint32の0番目に100を格納する Atomics.store(int32, 0, 100); // 待っているスレッドに書き込みが完了したことを伝える Atomics.notify(int32, 0, 1);
このように別スレッドの処理が終わるまで処理を待つ事ができます。
しかし、Atomics.wait
は同期処理です。
そのためメインスレッドで使ってはいけません。もしメインスレッドでスリープが実行されると、スリープしている間他の処理も止めることになります。
そこでAtomics.wait
を非同期で実行できるようにしたのがAtomics.waitAsync
です。`Atomics.waitAsync
はメインスレッドでも使えます。Promiseを返す関数になっています。
const sab = new SharedArrayBuffer(16); const int32 = new Int32Array(sab); const atom = Atomics.waitAsync( int32, // 対象のtypedArray 0, // typedArrayのindex 0, // 検証する値 1000 // タイムアウトする時間 ); atom.value.then( (value) => { if (value == 'ok') { // タイムアウトしなかった場合 console.log(int32[0]); // 100 } else { // タイムアウトした場合 console.log('Timeout!') } }); Atomics.store(int32, 0, 100) Atomics.notify(int32, 0, 1);
Atomics.wait
、Atomics.notify
、Atomics.waitAsync
については次のV8の記事が詳しいです。
RegExp match indices
正規表現でキャプチャグループの配列のインデックスを取得できます。V8 9.0で追加された機能です。
次のように/d
フラグをつけることで.indices
というプロパティが追加されます。.indices
にはキャプチャグループの配列のそれぞれの始点と終点のindexが格納されています。
// 'foo'と'bar'をキャプチャします const regex = /(foo)(bar)/d; // 文字列がマッチする const match = regex.exec('foobar'); // [ 'foobar', 'foo', 'bar' ] console.log(match.indices); // [ [ 0, 6 ], [ 0, 3 ], [ 3, 6 ], groups: undefined ] console.log(match.indices[0]); // [ 0, 6 ] 'foobar'が一致している console.log(match.indices[1]); // [ 0, 3 ] 'foo'が一致している console.log(match.indices[2]); // [ 3, 6 ] 'bar'が一致している
RegExp match indicesについてもV8のブログが詳しいです。
Timers Promises APIが安定版になりました
すでにNode.js v15でも追加されていたtimers/promises
モジュールが安定版になりました。
これは非同期でsetTimeout
のようなタイマー処理をするためのAPIです。
const { setTimeout: sleep } = require("timers/promises"); const main = async () => { console.log("start"); await sleep(10000); // 10秒待つ console.log("waited 10 seconds"); };
timers/promises
には3つの関数があります。
- setTimeout: 指定したミリ秒が経てばPromiseがresolveになる
- setImmediate: 現在のイベントループが終わったら、すぐ実行
- setInterval: 指定したミリ秒で繰り返し実行する
それぞれ使ったコードは次のとおりです。それぞれのタイマー処理がresolveされれば、それぞれのメッセージを表示しています。
import { setTimeout, setImmediate, setInterval } from 'timers/promises'; setTimeout(3000, '3秒後に実行').then(console.log); setImmediate('すぐ実行').then(console.log); for await (const time of setInterval(1000, Date.now())) { const now = Date.now(); console.log('経過時間:', now - time); }
$ node timers.mjs すぐ実行 経過時間: 1006 経過時間: 2016 3秒後に実行 経過時間: 3018 経過時間: 4027 経過時間: 5027
この数バージョンで非同期関数のPromise版がどんどん増えています。fs/promises
に関しては、実際使っている方も多いのではないでしょうか。今回紹介したtimers/promises
も使う頻度が高そうだなと感じています。
fs.rmdirのrecursiveオプションがDeprecatedになりました
fs.rmdir
関数、fs.promises.rmdir
、fs.rmdirSync
のrecursive
オプションがDeprecatedになりました。recursive
オプションは将来的に無視されるようになります。
元々、ドキュメント上ではDeprecatedになっていましたが、v16.0.0からは実行時にDeprecatedの警告メッセージが表示されるようになります。
recursive
オプションを付与することで、指定されたパスのサブディレクトリを再帰的に削除します。rm
コマンドの-r
オプションと同じ機能です。
たとえば、次のようなrmdirSync
関数にrecursive
オプションを使ったコードを実行してみます。
import fs from 'fs'; fs.rmdirSync('./path', { recursive: true });
実行しますが、次のような警告メッセージが表示されます。
(node:45355) [DEP0147] DeprecationWarning: In future versions of Node.js, fs.rmdir(path, { recursive: true }) will be removed. Use fs.rm(path, { recursive: true }) instead (Use `node --trace-deprecation ...` to show where the warning was created)
代わりにrm
関数でrecursive
オプション使って再帰的にディレクトリを削除できます。
また、rm
関数にはforce
オプションが追加されています。force
オプションはrm
コマンドの-f
オプションのようにディレクトリを強制的に削除できるオプションです。force
オプションの指定は省略できます。省略したとき、内部的にfalse
が設定されます。
recursive
オプションとforce
オプションをtrue
にすると、rm -rf
コマンドと同じことができます。
import fs from 'fs'; fs.rmSync('./path', { recursive: true, force: true });
前述のとおり、将来的にrmdir
関数のrecursive
オプションは無視されるようになります。今後はrm
関数を使いましょう。
Node.js v15の機能がLTSとして使えるようになる
Node.js v15の紹介ブログでも書いたとおり、Node.js v15には多くの機能が追加されています。
上記の記事で紹介しただけでも次の機能が追加されます。
- npm v7がNode.jsに同梱される
- ES2021の新機能
- Web Crypto API (まだExperimental)
- AbortController
- EventTarget
- QUIC (まだExprimental)
- stream/promises
- Unhandle Rejectionsの終了ステータスが
1
に変更
これらに加えて、マイナーバージョンでBuffer
にatob
とbtoa
が追加されています。
Node.js v15の機能はもちろんNode.js v16に含まれています。LTSとして多くの機能が使えるようになります。Node.js v16がLTSになるのは2021/10/26を予定しています。
最後に
Node.js v16の変更は少なく感じますが、Node.js v15で追加された機能も含みます。本番環境でLTSのNode.jsを使っている方などには大きな変更になるのではないでしょうか。
特にnpm v7やUnhandled Rejectionsの終了ステータスは大きな変更です。Node.js v16へアップデートする前に検証しておくことをおすすめします。
Node.jsは4月末と10月末にメジャーバージョンのリリースをします。次のv17は10月末ごろにリリースされるはずです。また、今回紹介したNode.js v16は2021/10/26にLTSになります。
最新のリリース情報は以下のリポジトリでご確認ください。
最後までお読みいただきありがとうございました。不備や質問がございましたら、@shisama_までメンションするかブコメなどでコメントください。
参考記事
変更履歴
- (2021/04/22)「fs.rmdirのrecursiveオプションがDeprecatedになりました」の節に
rm
関数に関する内容を追記しました。