(サンプル1) Promise を直接使う場合 (v10.x.x)
async/await の使い方のサンプルはたくさんあるが、Node.js のモジュール関数(非同期)で実際に使うサンプルがなかった(少ない)ので、試しに作ってみた。
なお、使った Node.js のバージョンは 10.15.2 である。このバージョンでは fsPromise は experimental であるので警告が出る。気になる場合は v12 以上を使う必要がある。
次のサンプルは、fs.mkdir(path[, options], callback) の使用例である。/home/user/temp というフォルダの下にsub1を作り、さらに sub1/sub2 を作り、最後に sub1/sub2/sub3 を作る。
/* ディレクトリ作成 c:/temp/sub1/sub2/sub3 を作成 */
'use strict';
const fs = require("fs");
const dir0 = "/home/user/temp/";
const dir1 = "sub1/";
const dir2 = "sub2/";
const dir3 = "sub3/";
/* 指定したディレクトリを非同期で作成する。*/
function make_dir(dir) {
return new Promise(resolve=>{
fs.mkdir(dir, err=>{
resolve(err);
});
});
}
/* ディレクトリ作成をここで順番に実行する。return で値を返さないこと。*/
async function makedirs_exec() {
let err;
let dir = dir0 + dir1;
err = await make_dir(dir);
if (err != null) {
console.log(err.message);
return;
}
dir += dir2;
err = await make_dir(dir);
if (err != null) {
console.log(err.message);
return;
}
dir += dir3;
err = await make_dir(dir);
if (err != null) {
console.log(err.message);
return;
}
console.log("END");
}
/* サブディレクトリを順番に作成する。*/
makedirs_exec();
await は async 関数の中でしか使えない。 await できる関数は Promise オブジェクトを返す必要があり、その内部でペンディングが解消したとき、resolve() を呼び出す必要がある。
上の例では、make_dir(dir) がその関数である。
async 関数は makedirs_exec() であり、内部で await を使ってペンディングが解消するまで停止し、順に深い場所のサブディレクトリを作成している。
最後に、makedirs_exec() をコールして処理を実行している。
(サンプル2) fsPromise 関数を使う場合 (v12.x.x以上)
v10.x.x までは fsPromise 関数は正式にサポートされてないため、警告が出るが、v12.x.x では正式サポートされたようである。
ただし、大部分の関数は v10.x.x でも stable のようなのでv12.x.xでもコードを書き換えずにそのまま実行できると思われる。
次のサンプルは、fsPromise の rmdir(path) 関数を使って、前のサンプルで作ったディレクトリを削除する。
fsPromise モジュール関数では、関数自体が Promise オブジェクトを返すので、ラッパー関数 (サンプル1のmake_dir(dir)に相当) を作る必要がなく、実にシンプルになる。
/* fsPromise の rmdir 関数を使ってディレクトリを削除する例 */
const fs_p = require("fs").promises;
const dir1 = "/home/user/temp/sub1";
const dir2 = "/home/user/temp/sub1/sub2";
const dir3 = "/home/user/temp/sub1/sub2/sub3";
async function remove_dirs() {
/* sub3 を削除 */
let err = await fs_p.rmdir(dir3);
if (err == null) {
console.log(`${dir3} was deleted.`);
}
else {
console.log(err.message);
return;
}
/* sub2 を削除 */
err = await fs_p.rmdir(dir2);
if (err == null) {
console.log(`${dir2} was deleted.`);
}
else {
console.log(err.message);
return;
}
/* sub1 を削除 */
err = await fs_p.rmdir(dir1);
if (err == null) {
console.log(`${dir1} was deleted.`);
}
else {
console.log(err.message);
return;
}
console.log("Done.");
}
/* 開始 */
remove_dirs();
(サンプル3) 複数のモジュール関数を使う例 (v10.x.x)
ここでは、複数のモジュール関数を使うやや複雑な例を示す。
サンプル1では常にエラーがないものとして、resolve() でペンディングを解消していたが、ここではエラー時には reject() でエラー処理をするようにした。
この例では、fs.open でファイルを開いて、fs.read で内容を読み込み、最後に fs.close する。
/* 非同期関数を使ってファイルを読む。*/
'use strict';
const fs = require("fs");
const PATH = "/home/user/bin/myuser";
const BUFFLEN = 1024;
var arraybuffer = new Array(1024);
var buffer = Buffer.from(arraybuffer);
/* ファイルを開く */
function open_file(path) {
return new Promise((resolve, reject)=>{
fs.open(path, "r", (err, fd)=>{
if (err == null)
resolve(fd);
else
reject(err);
});
});
}
/* バッファにファイル内容を読み込む。(バッファ長より短いファイルのみ) */
function read_fd(fd) {
return new Promise((resolve, reject)=>{
fs.read(fd, buffer, 0, BUFFLEN, null, (err, bytesRead, buffer)=>{
if (err == null)
resolve(bytesRead);
else
reject(err);
});
});
}
/* ファイルを閉じる */
function close_fd(fd) {
return new Promise((resolve, reject)=>{
fs.close(fd, (err)=>{
if (err == null)
resolve(null);
else
reject(err);
});
});
}
/* 非同期関数を呼び出してファイルの長さと内容を表示する。*/
async function read_file(path) {
try {
let fd = await open_file(PATH);
let bytes = await read_fd(fd);
console.log(bytes);
let s = buffer.join(",");
console.log(s);
await close_fd(fd);
console.log("Done.");
}
catch (e) {
console.log(e.message);
}
}
/* 実行開始 */
read_file(PATH);