NodejsのPromiseで再帰呼び出しを行う!JavaScriptの非同期処理がおもしろい。

こんにちは!
JavaScriptの週末プログラミングが面白すぎて、夜も眠れない、しずかなかずしです。
みなさんは、JavaScriptのPromiseという仕組みをご存知ですか??
元々は、サーバーサイドでJavaScriptを使う目的で登場したNodejs。このプラットフォームのために定義されたNodejsのAPIの数々は、なんでもかんでも非同期の形式なのです。
非同期、つまり、APIの一つの関数は、呼び出した直後には結果が得られないような形式。
プログラマーが関数呼び出しの結果を受け取るために、APIの関数呼び出し時に自前のコールバック関数を登録する必要があります。結果は、API内部からコールバック関数が呼び返されてはじめて得られる、という仕組み。
単にファイルをオープンするだけの処理も非同期。逆に、あえて同期(つまり、呼び出したら関数の戻り値として、結果が返る)関数は、関数名にSyncというキーワードが含まるれる、という徹底ぶり。


JavaScript固有の変数のスコープ(クロージャー)の考え方と、名前をつけなくても関数が定義できる「無名関数」という仕組みが、私のような古風なC言語世代にはとても斬新でした。
サーバーサイドで時間がかかる処理をなるべく待たせないという、このような設計上の工夫。これによって、パフォーマンスに対して有利でも、プログラム自体の見通しが悪くなることもしばしば。
そんな、見た目の悪い、コールバックスパゲッティコードを、わかりやすく書くことができる、目からウロコなテーマが、本日のネタ、Promiseなんです。
そして、週末プログラミングで、Promiseを使った関数を再帰的な呼び出しが必要になりました。
その結果のまとめ記事です。
非同期処理まとめ
まずは、非同期処理でコーティングするとどうなるのか、サンプルを使って見てみましょう。
サンプルとしては用意した課題は、非同期関数を3つ使った簡単なものです。
- ファイルa.txtを開く。開いた結果、file descriptor(fd)というファイル固有のIDを受け取る
- fdを使って、ファイルにhello world!を書く
- 開いたファイル(fd)を閉じる
1から3が全て非同期のAPIで実現するケースを考えます。Nodejsのfsオブジェクトを使ったものです。
実は、Nodejsには、これらをいっぺんにやってくれるAPIも用意されています(それも非同期)。ですが、ここではサンプルとして、あえて3つの非同期関数を連続して呼んでみます。
Callbackで普通に書く
上で述べた処理を、普通にコールバック関数を無名関数でコーティングすると、以下のようになります。
const fs = require('fs');
fs.open('a.txt', 'w', function(err, fd) {
if (err) {
console.log('cannot open file');
return;
}
fs.write(fd, 'Hello, world!', function(err) {
if (err) {
console.log('cannot write file');
return;
}
fs.close(fd, function(err) {
if (err) {
console.log('cannot close fd');
}
console.log('end!');
});
});
});
コールバック関数の中で次の処理、そのコールバックで次の処理と、関数がネストされていき、なんとも書きにくいし、読みにくいプログラムになってしまいます。
かんたんに中身の説明します。
まず、fs.open()でファイルを開きます。この関数は非同期なので、コールバック関数を引数に設定します。
コールバック関数のパラメータとしてfdが返ってくるので、それを使って、今度はfs.write()でテキストをファイル(fd)に書き込みます。この関数にも、コールバックを設定します。これは、データが書き終わった後に呼ばれるコールバックです。
その関数の中で、openしたfdを閉じるために、fs.closeを呼び出します。
この例は、処理が単純なのでまだ良いのですが、コールバック関数の中の処理が複雑になってくると、何してるのかわからなる事態は、容易に想像できます。
Promiseを使って書く
Promiseの場合は、コールバック関数を登録する代わりに、APIがPrimiseのオブジェクトを返します。
その戻りオブジェクトのthen()の中で、次の処理をするための関数を呼び出します。この関数もPromiseオブジェクトを返すので、さらに、続けてthen()を呼んで、といった感じで非同期の処理を順番に呼び出して行きます。
実際の関数ソースです。
my_open('a.txt').then(function(fd) {
return my_write(fd, 'Hellow, world!');
}).then(function(fd) {
return my_close(fd);
}).then(function() {
console.log('end!');
}).catch(function(err) {
console.log(err);
});
コールバックを使った場合と比較すると、とてもシンプルです。
なんでこんなかんたんに書けるのか?
これこそが、Promiseの仕業なのです!
それでは上記のコードで使っている、my_open, my_write, my_closeの実装を見てみましょう。
オリジナルのnodejsの、コールバック関数を引数に取るAPIを、それぞれpromiseで書き直したものがこれです。
const fs = require('fs');
function my_open(filename) {
return new Promise(function (resolve, reject) {
fs.open(filename, 'w', function(err, fd) {
if (err) reject('cannot open file');
else resolve(fd);
})
})
}
function my_write(fd, str) {
return new Promise(function (resolve, reject) {
fs.write(fd, str, function(err) {
if (err) reject('cannot write file');
else resolve(fd);
});
});
}
function my_close(fd) {
return new Promise(function(resolve, reject) {
fs.close(fd, function(err) {
if (err) reject('cannot close fd');
else resolve();
});
});
}
本当は、上記と同じ処理をするPromiseタイプのAPIが既にあればよいのです。しかし、コールバックタイプの関数でも、こんな感じで書き換え可能なのです。
やり方としては、Promiseオブジェクトのコンストラクタに関数を書き、その中でコールバックタイプの関数呼び出しを実行。戻ってくるコールバックが正常だった場合は、resolve()を呼び、エラーだったらreject()を呼ぶ、といった感じ。定形的でシンプルです。
再帰呼び出しでやりたいこと
さて、Promiseがわかったところで、実際に私がやりたかった非同期処理に話を移します。
ある木構造の上から下に向かって階層を順繰りにたどり、階層毎に一つの処理を実行するようなケースを考えます。木構造の上の要素が、その直後に階層的に下の要素の処理結果に影響する、そんなケースです。
そして、各階層はデータベースにアクセスする処理で、非同期に実行することが期待です。
このようなケースでは、各階層で行う処理は、対象となるデータが異なるものの、処理の中身は毎回一緒。そして、とある階層の処理を実行するためには、前の階層の処理結果を使用します。
条件が成立するまで、木構造の階層をたどって同じ処理を実行し続けます。
こういった処理を関数の再帰呼び出しで実行してしまおう、というのがお題。そして、関数は非同期に結果が返るので、Promiseの登場となるのです。
Promise再帰呼び出しコード例
上記のケースを想像しつつ、話を簡単にするために処理の流れだけを中心にコードを書きます。
単純化しているため、これだけのことなら、ループ回せば事足りると思うかも知れません。
しかし、本来は上述のように、一つ前の結果が次の処理の入力になる仕事をするのが目的です。そのつもりでコードを読んで下さい。
var fs = require('fs');
// prepare data
var test_array = ['Hello', 'World', '!', 'Hello, world!'];
// call recursive function with array
recursive_function(test_array).then(() => {
console.log('finish');
}).catch((e) => {
console.log('err: '+e);
})
// processing just one item on the array asynchronously.
function process_one_item(param) {
return new Promise((resolve, reject) => {
fs.writeFile('a.txt', param+'\n', {flag:'a+'}, (err) => {
if (err) reject(err);
else resolve();
});
});
}
// function that called recursively
function recursive_function(array) {
return new Promise((resolve, reject) => {
if (array.length<1) {
resolve();
} else {
process_one_item(array[0]).then(() => {
// call next cycle with shifted array
array.shift();
recursive_function(array).then(() => {
resolve();
});
}).catch((e) => {reject(e);});
}
});
}
配列test_arrayを文字列で初期化していますが、これが木構造をたどるためのキーになるデータだと思って下さい。
一応、こんな感じのコードで期待通りに動作して、目的は果たせています。
しかし、なんとなく、もっといい方法がありそうな気がしています。気がついたらまた記事にします。
ということで、本日はここまで。最後まで読んで頂き、ありがとうございました!
ディスカッション
コメント一覧
cloriquine
[url=https://chloroquineorigin.com/#]chloroquine hcl[/url]
what erectile dysfunction
[url=https://erectiledysfunctionpillscvs.com/#]online doctor erectile dysfunction[/url]
hydroclorizine
[url=https://hydroxychloroquinex.com/#]covid 19 who[/url]
erectile ointment
[url=https://plaquenilx.com/#]stopping plaquenil[/url]
tadalis 20
[url=https://tadalisxs.com/#]order tadalafil[/url]
citramax
[url=https://zithromaxes.com/#]zithromax order online[/url]
cbd gummies walmart [url=https://cbdcreamshs.com/ ]cbd [/url] just cbd gummies cbd oil amazon https://cbdcreamshs.com/
erectile muscle https://plaquenilx.com/ problems with erectile dysfunction
chloroquinine https://chloroquineorigin.com/ chloroquine moa
malaria usmle https://hydroxychloroquinex.com/ hydroxychloroquine and chloroquine side effects
casino play [url=https://playcasinovivo.com/ ]best online casino [/url] online slot games slots for real money online casinos
online casino real money casino online slots no deposit casino
online casino gambling free casino games online play online casino vegas casino slots
best online casinos vegas casino slots play casino online casino bonus [url=https://playcasinovivo.com/ ]vegas slots online [/url]
casino real money casino blackjack slots free big fish casino
cbd online [url=http://cbdoilforpainrx.com/# ]buy hemp oil [/url] cannabis oil cbd oil cdb oils
casino games play online casino free casino games online casino games [url=https://playcasinovivo.com/ ]real casino slots [/url]
cbd gummies walmart [url=http://cbdoilforsalejmm.com/# ]pure cbd oil [/url] cbd cbd gummies walmart cbd hemp
cdb oils [url=http://cbdhempoildk.com/# ]hemp cbd [/url] cbd pills best cbd
hemp cbd oil buy cbd oil cbd near me pure cbd
cbd hemp cbd oil near me best cbd oil
cdb oils cbd pills cannabis oil
cbd oil store [url=http://buycbdoilfo.com/# ]cbd drops [/url] cdb oils cbd oil for sale
casino online slots [url=https://onlinecasinosw.com/ ]real money casino [/url] play slots online casino slots free casino games online
free casino games online [url=https://onlinecasinosw.com/ ]slots games free [/url] free online slots play online casino
hemp cbd buy cannabis oil cbd near me cbd tinctures [url=http://annabisoilweb.com/# ]cbd products [/url]
cbd cbd drops buy cbd
cbd drops buy cbd oil pure cbd cbd products [url=http://hempcbdoilgh.com/# ]cbd oil for sale [/url]
online casino gambling [url=https://onlinecasinosw.com/ ]free slots [/url] no deposit casino best online casino
best cbd oil [url=http://buycbdoilonlinerru.com/# ]cbd cream [/url] cbd gummies walmart cbd oil online
slots free casino online slots slots for real money online casino gambling [url=https://onlinecasinosw.com/ ]slots games [/url]
online casino games casino online online slots casino blackjack [url=https://onlinecasinosw.com/ ]best online casinos [/url]
online casino [url=https://onlinecasinosw.com/ ]play online casino [/url] slot games play online casino vegas casino slots
online gambling [url=https://onlinecasinosw.com/ ]no deposit casino [/url] free slots games vegas casino slots
best online casino free casino slot games free online slots
best cbd buy cbd oil cbd store buy cbd oil [url=http://cbdcreamshs.com/# ]cbd oil benefits [/url]
online slot games [url=https://onlinecasinosw.com/ ]real money casino [/url] play slots casino real money https://onlinecasinosw.com/
cbd oil benefits [url=http://purecbdok.com/# ]cbd oil store [/url] cbd tinctures medterra cbd
viagra prices [url=https://viagrafirst.com/ ]viagra [/url] viagra no prescription viagra prescription https://viagrafirst.com/
best online casino [url=https://playslotsndx.com/ ]casino games [/url] free casino games online free casino games online https://playslotsndx.com/
best online casino casino online casino online slots slots for real money [url=https://playslotsndx.com/ ]big fish casino [/url]
erectafil 20 side effects https://tadalisxs.com/ tadalafilo 20 mg
generic viagra [url=https://viagrafirst.com/ ]viagra generic [/url] buy viagra buy viagra online viagra for men
cbd hemp buy cbd oil online hemp cbd oil cbd oil online
medterra cbd [url=http://buycbdoilonlinerru.com/# ]cbd oil benefits [/url] cbd for sale cbd store
casino games [url=https://playslotsndx.com/ ]online casino gambling [/url] play slots no deposit casino free casino games online
buy hemp oil cbd oil buy cannabis oil cbd oil for sale
cbd pills [url=http://cbdoilstoretv.com/# ]cbd near me [/url] cannabis oil buy hemp oil
play online casino online casino slots online slot games
pure cbd [url=http://cannabisoilhemp.com/# ]pure cbd [/url] cbd oil online hemp cbd cbd
buy cannabis oil [url=http://cbdoilforsalejmm.com/# ]cbd tinctures [/url] best cbd hemp cbd
cbd pills [url=http://cbdhempamp.com/# ]cbd oil [/url] buy hemp oil cbd tinctures full spectrum cbd oil
best online casinos free casino games online no deposit casino slots for real money
casino bonus codes [url=https://onlinecasinos911.com/ ]play slots online [/url] casino games online casino slots
viagra pill [url=https://viagrafirst.com/ ]cheap viagra [/url] cheap viagra buy viagra viagra prescription
cbd hemp hemp cbd oil cdb oils cbd gummies walmart [url=http://cbdstorejj.com/# ]cbd gummies walmart [/url]
pure cbd cbd products buy cannabis oil
best cbd oil [url=http://cbdstorejj.com/# ]buy hemp oil [/url] buy hemp oil cbd store
casino online slots [url=https://onlinecasinos911.com/ ]casino blackjack [/url] online slots slot games casino real money
cbd oil pure cbd cbd oils cbd [url=http://cbdcreamshs.com/# ]buy cbd oil online [/url]
date sites [url=http://onlinedatingdd.com/ ]senior dating sites [/url] bbw dating dating site for gay teen
top dating sites christian dating for free dating naked free dating sites [url=http://onlinedatingdd.com/ ]tinder dating site [/url]
viagra for sale viagra online viagra online viagra pills [url=https://viagrafirst.com/ ]buy viagra pills [/url]
online casino real money [url=https://onlinecasinogsw.com/ ]casino games [/url] free slots free casino slot games
viagra no prescription [url=https://viagrafirst.com/ ]viagra pill [/url] buy viagra viagra prescription viagra prescription
free casino games online [url=https://onlinecasinogsw.com/ ]casino blackjack [/url] casino games casino online slots play casino
casino bonus codes free slots games real money casino casino online [url=https://onlinecasinogsw.com/ ]online casinos [/url]
online gambling [url=https://onlinecasinogsw.com/ ]online slots [/url] online slots free slots play slots online
casino bonus codes [url=https://onlinecasinogsw.com/ ]online slots [/url] casino slots casino slots
free casino [url=https://onlinecasinogsw.com/ ]online slots [/url] real casino slots play slots online
best online dating sites [url=http://onlinedatingdd.com/ ]christian dating sites [/url] russian dating tender dating
play casino play casino real casino slots slots games free
no deposit casino online casino games casino slots online slots
play online casino [url=https://casinorealmoneyiw.com/ ]online casino real money [/url] casino bonus codes slot games online casino games
vegas casino slots best online casinos free slots
top dating sites [url=http://onlinedatingdd.com/ ]dating [/url] top dating sites interracial dating
bumble dating app best dating sites dating site best dating profiles [url=http://onlinedatingdd.com/ ]facebook dating [/url]
tinder dating site interracial dating tender dating
dating websites [url=http://onlinedatingdd.com/ ]hookup sites [/url] facebook dating app best dating sites best dating profiles
best dating profiles [url=http://onlinedatingdd.com/ ]dating site for gay teen [/url] best dating web sites bumble dating app facebook dating app
casino online real casino slots play online casino
best online casinos [url=https://casinogamesww.com/ ]free casino slot games [/url] casino blackjack free casino slot games casino game
best dating web sites [url=http://onlinedatingdd.com/ ]facebook dating site [/url] best online dating zoosk online dating site adult dating sites
bbw dating free dating websites dating sites
free online slots [url=https://casinoonlineww.com/ ]no deposit casino [/url] casino slots slots online
free dating site free dating sites no fees interracial dating dating sim [url=http://onlinedatingdd.com/ ]facebook dating app [/url]
best online dating local dating russian dating
best dating web sites [url=http://onlinedatingdd.com/ ]facebook dating site [/url] christian dating sites russian dating
health insurance. gov – cialis Epdee86
cialis 20 yan etkileri
over the counter viagra type: [url=https://www.withoutbro.com/]buy viagra online[/url]
erectile tissue problems [url=https://plaquenilx.com/#]plaquenil blindness[/url] treating erectile dysfunction without drugs
hydrochloraquine [url=https://hydroxychloroquinex.com/#]coronavirus treatment[/url] hcqs side effects
You actually explained that adequately. https://www.goldkamagra.com kamagra srbija Ovfc72x
what is zithromax used for in adults [url=https://zithromaxes.com/]where can i purchase zithromax[/url] uses of zithromax
Thank you for any other excellent article. Where else may just anyone get that kind of info in such a perfect way of writing? I’ve a presentation subsequent week, and I am at the look for such information.
Heya i’m for the first time here. I came across this board and I to find It truly useful & it helped me out a lot. I hope to give something back and aid others like you helped me.
You revealed it wonderfully! https://www.kamagramama.com kamagra consecuencias Agitcyq
hey there and thank you for your information ? I have definitely picked up anything new from right here. I did however expertise some technical issues using this web site, since I experienced to reload the site many times previous to I could get it to load properly. I had been wondering if your hosting is OK? Not that I am complaining, but slow loading instances times will sometimes affect your placement in google and could damage your quality score if ads and marketing with Adwords. Well I am adding this RSS to my email and could look out for much more of your respective fascinating content. Make sure you update this again very soon..
canadian pharmacy
tadalafil 10mg india buy megalis uk