Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9145

Node.js/Typescript で async-lock を使って非同期処理を同期処理風に記述

$
0
0
Node.js でファイルアクセスや DB アクセスなどの非同期処理を連続して記述しようとすると、非同期処理の callback がネストしてプログラムが読みにくくなってしまいます。 (書く方もつらい。。。) そこで、async-lock を使って連続する非同期処理を同一のロック変数でロックすることで、ネストを深くせずに同期処理風に記述できないか、試してみました。 非同期処理の記述 ここでは以下のような処理を順次実行する場合を考えます。 1. ファイル1 を読み込み、変数1 に保存 2. ファイル2 を読み込み、変数2 に保存 3. ファイル3 へ変数1 の値を書き込み 4. ファイル4 へ変数2 の値を書き込み 上記の処理内容を readFile、writeFile で callback を記述すると、以下のようにネストが深いプログラムになってしまいます。 fs.readFile(file1, (err, data1) => { // 処理1 fs.readFile(file2, (err, data2) => { // 処理2 fs.writeFile(file3, data1, (err) => { // 処理3 fs.writeFile(file4, data2, (err) => { // 処理4 }); }); }); }); ※ファイル入出力に限らず非同期処理の記述方法を検証するため、読み書き処理で readFileSync()、writeFileSync() は使わないものとします。 async-lock による排他制御 async-lock は排他制御を行うためのライブラリです。 https://www.npmjs.com/package/async-lock サンプルとして、以下のような例が紹介されています。 var AsyncLock = require('async-lock'); var lock = new AsyncLock(); lock.acquire(key, function(done) { // async work done(err, ret); }, function(err, ret) { // lock released }, opts); key がロック変数で、// async work に排他する処理を記述します。 async-lock を利用した非同期処理の記述 例に挙げた4つの非同期処理を逐次実行するようにするため、async-lock で同一のロック変数を使って排他制御することで、各非同期処理を逐次実行するようにプログラムを記述してみます。 import * as fs from 'fs'; import AsyncLock from 'async-lock'; function main() { let var_1 = '--'; let var_2 = '--'; const lock = new AsyncLock(); // file1.txt から読み込み lock.acquire('sync', (done: any) => { const file = 'file1.txt'; console.log('before read ' + file); fs.readFile(file, 'utf-8', (err, data) => { if (err) { console.log('error: failed to read ' + file); } else { var_1 = data; console.log(var_1); console.log('after read ' + file); } done(); }); }); // file2 から読み込み lock.acquire('sync', (done: any) => { const file = 'file2.txt'; console.log('before read ' + file); fs.readFile(file, 'utf-8', (err, data) => { if (err) { console.log('error: failed to ' + file); } else { var_2 = data; console.log(var_2); console.log('after read ' + file); } done(); }); }); // file3 へ書き込み lock.acquire('sync', (done: any) => { const file = 'file3.txt'; console.log('before write to ' + file); fs.writeFile(file, var_1, (err: any) => { if (err) { console.log('error: failed to ' + file); } else { console.log('after write to '+ file); } done(); }); }); // file4 へ書き込み lock.acquire('sync', (done: any) => { const file = 'file4.txt'; console.log('before write to ' + file); fs.writeFile(file, var_2, (err: any) => { if (err) { console.log('error: failed to ' + file); } else { console.log('after write to ' + file); } done(); }); }); // 変数の値を出力 lock.acquire('sync', (done: any) => { console.log('var_1'); console.log(var_1); console.log('var_2'); console.log(var_2); done(); return 0; }); } console.log('before main'); main(); console.log('after main'); 上記のプログラムを実行した結果は以下の通りです。(※はコメント) before main before read file1.txt ※file1 から読み込み after main ※★ abcdef after read file1.txt before read file2.txt ※file2 から読み込み read: 123456 after read file2.txt before write to file3.txt ※file3 へ書き込み write: abcdef after write to file3.txt before write to file4.txt ※file4 へ書き込み after write to file4.txt var_1: abcdef ※var_1 の内容 var_2: 123456 ※var_2 の内容 プログラムの実行結果を見てみると、 file1 から読み込み ⇒ file2 から読み込み ⇒ file3 へ書き込み ⇒ file4 へ書き込み の順で実行されていることがわかります。 しかし、★の after main は main() の実行後に表示されるメッセージで、自分の意図とは異なり、一連のファイル読み書き処理後に実行されずに、すり抜けてしまいました。 最後に async-lock を使うことで、一連の非同期処理を同期処理風に記述することができました。 しかし、意図しないすり抜けが発生しているため、調査してみたいと思います。

Viewing all articles
Browse latest Browse all 9145

Trending Articles