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
何も考えないで実装した場合
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を利用した場合
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
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サイトです。怒られたら変更しよう!
以上


