【node.js】非同期処理

node.js で何回かHTTP通信をしたときの対応。

node.jsはシングルスレッドで動作します。
さらにノンブロッキングなので同期的な処理は基本しません。
なのでHTTP通信を行って、結果を待って、次の処理というのは
普通に書くとネスト地獄になりコードの可読性が著しく悪くなります。
ということで今回は「Promise」を使用しました。

本当は「sync-request」を使おうと思ったのですが
非推奨?なのかあまり使うなと書かれていたので、今回はパス!

あと一応命名や文法も気にはしてますが、完全に守れてはいないのあしからず・・・
http://cou929.nu/data/google_javascript_style_guide/
http://popkirby.github.io/contents/nodeguide/style.html

何も考えないで実装した場合

app.js

const https = require ('https');
const url = require('url');
const ACCESS_URL = 'https://www.itcowork.co.jp/';
const opt = url.parse(ACCESS_URL);
opt.method = 'GET';
console.log('START');
// 変数を宣言
var code;
var body;
var req = https.request(opt, (res) => { console.log('status code : ' + res.statusCode); code = res.statusCode; body = ''; res.on('data', (chunk) => { body += chunk; console.log('data'); }); res.on('end', () => { console.log('end'); });
})
req.on('error', (err) => { console.log('request error : ' + err.message);
});
req.end();
console.log('LAST CHECK : ' + code);
console.log('END');
START
LAST CHECK : undefined
END
status code : 200
data
end

先に「LAST CHECK」が出てあとからHTTP処理の結果が出ています。
1個だけHTTP処理をする分にはこれでも大丈夫です。
もしくは「end」の処理の部分に別Functionを呼び出してネストしまくるとか
でも一応は対応できます。

が、今回はもっとスマートに書きたいので「Promise」を使用します。

Promiseを利用した場合

app.js

const https = require ('https');
const url = require('url');
const ACCESS_URL = 'https://www.itcowork.co.jp/';
const opt = url.parse(ACCESS_URL);
opt.method = 'GET';
console.log('START');
test1().then((value) => { console.log('status code : ' + value); console.log('END');
}, (err) => { console.error("error:", err.message);
});
function test1(){ return new Promise ((resolve, reject) => { var req = https.request(opt, (res) => { console.log('1.status code(function) : ' + res.statusCode); var code = res.statusCode; var body = ''; res.on('data', (chunk) => { body += chunk; console.log('1.data'); }); res.on('end', () => { console.log('1.end'); resolve(code); }); }) req.on('error', (err) => { console.log('1.request error : ' + err.message); reject(err) }); req.end(); });
}
START
1.status code(function) : 200
1.data
1.end
status code : 200
END

Promiseオブジェクトを作成して、thenで実行し実行結果を取得しました。
正しい順序でログが出てることがわかります。

複数回HTTP通信

次に複数回のHTTP通信の実装です。
お試しなのでHTTP通信先はまったく同じですごめんなさいm(_ _)m

app.js

const https = require ('https');
const url = require('url');
const ACCESS_URL = 'https://www.itcowork.co.jp/';
const opt = url.parse(ACCESS_URL);
opt.method = 'GET';
console.log('START');
var promise = Promise.resolve();
promise .then(test1) .then((result) => { return new Promise(function(resolve, reject){ console.log("1.status code : " + result); resolve(1); }); }) .then(test2) .then((result) => { return new Promise(function(resolve, reject){ console.log("2.status code : " + result); resolve(2); }); }) .catch(onRejectted);
function test1(){ return new Promise ((resolve, reject) => { var req = https.request(opt, (res) => { console.log('1.status code(function) : ' + res.statusCode); var code = res.statusCode; var body = ''; res.on('data', (chunk) => { body += chunk; console.log('1.data'); }); res.on('end', () => { console.log('1.end'); resolve(code); }); }) req.on('error', (err) => { console.log('1.request error : ' + err.message); reject(err) }); req.end(); });
}
function test2(){ return new Promise ((resolve, reject) => { var req = https.request(opt, (res) => { console.log('2.status code(function) : ' + res.statusCode); var code = res.statusCode; var body = ''; res.on('data', (chunk) => { body += chunk; console.log('2.data'); }); res.on('end', () => { console.log('2.end'); resolve(code); }); }) req.on('error', (err) => { console.log('2.request error : ' + err.message); reject(err) }); req.end(); });
}
function onRejectted(error) { console.log("error:" + error);
}
START
1.status code(function) : 200
1.data
1.end
1.status code : 200
2.status code(function) : 200
2.data
2.end
2.status code : 200

もし「test1」と「test2」のFunctionに引数を渡す場合は
以下のように呼び出せば正しく動作します。

var promise = Promise.resolve();
promise .then((result) => { return test1(1); }) .then((result) => { return new Promise(function(resolve, reject){ console.log("1.status code : " + result); resolve(1); }); }) .then((result) => { return test2(2); }) .then((result) => { return new Promise(function(resolve, reject){ console.log("2.status code : " + result); resolve(2); }); }) .catch(onRejectted);

途中でエラーにしたい場合は以下のようにすればOKのはず

var promise = Promise.resolve();
promise .then(test1) .then((result) => { return new Promise(function(resolve, reject){ console.log("1.status code : " + result); if(result == 404) reject(new Error("わざとエラー")); //resolve(1); }); }) .then(test2) .then((result) => { return new Promise(function(resolve, reject){ console.log("2.status code : " + result); resolve(2); }); }) .catch(onRejectted);
START
1.status code(function) : 404
1.data
1.end
1.status code : 404
error:Error: わざとエラー

まとめ

久しぶりに複数処理を書きましたが、
非同期とか久しぶりすぎて忘れてました!
そして未だにアロー関数(=>)に慣れませんw

ちなみにソース中でHTTPアクセスしてるのは
前職のWEBサイトです。怒られたら変更しよう!

以上

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください