Edited at

setTimeoutを利用せず、JavascriptのPromiseだけで複数のCallback関数を順番で実行する


はじめに

  私みたいに毎回Callback関数を順番で実行させるために色んなライブラリーの導入かsetTimeout()を利用する人がいると思います。今回はライブラリーの導入が無しでPromiseだけで複数のCallbackを順番に実施する方法を共有します。


これから説明するモノの仕組み

  どうしても一回のSQL文ではresponseで返したいものすべてが取れないとき、または複数のDBを利用するときDB1の結果がDB2の入力になってしまうことがあると思います。そのときには複数のCallback関数ができてしまいますが、個人的にはCallbackの中にCallback関数を入れるやり方だと今後改修時にわけわからなくなるではないかと思って、Promiseで解決する方法調べました。(参考してた文章がみつからなくてすみません。)

  今回は以下のような仕組みのときのやりかたを紹介します。

  ここでfunc1の出力を用いてfunc3を複数回呼び出すことになっています。

image.png

上から順番に書き方を説明します。


SQL.jsとNoSQL.jsの書き方

SQL.jsは例としてmySQLの書き方を紹介します。

var mysql      = require('mysql');

var dbconfig = require('../config/mysql.json');
var connection = mysql.createPool({
host : dbconfig["hostname"],
user : dbconfig['userName'],
password : dbconfig["password"],
database : dbconfig["dbName"]
});

exports.func1 = function(columnValue){
return new Promise(function(resolve, reject) {
connection.query("select * from TABLE1 where COLUMN = ?",[columnValue], function (error, results, fields) {
if(error) reject(error);
else {
console.log(results);
resolve(results);
}
});
});
}
//func2も書き方が同じですので省略します。

noSQL.jsの書き方も上と同じです。MongoDBの例をあげます。

var MongoClient = require('mongodb').MongoClient;

var dbconfig = require('../config/mongo.json');

var url = dbconfig["base_url"]
+dbconfig["host"]
+":"
+dbconfig["port"]
+"/"
+dbconfig["database"];

MongoClient.connect(url,{ useNewUrlParser: true }).then(db => {
console.log("Connected successfully to server")
db.close()
}).catch(err => {
console.log(err)
});

exports.func3 = function(id){
return new Promise(function(resolve, reject) {

MongoClient.connect(url,{ useNewUrlParser: true }).then(client => {
console.log("Connected successfully to server")
var db = client.db(dbconfig["dbName"]);
var collection = db.collection(dbconfig["collectionName"]);

collection.find({'_id': id}).toArray(function(err, docs) {
if(err) {
console.log(err);
reject(err);
}
console.log(docs);
client.close();
resolve(docs);
});
client.close();
}).catch(err => {
console.log(err)
});
});
}
//func4も書き方が同じですので省略します。


Controller.jsの書き方

'use strict';

var mysql = require('../service/mysql.js');
var mongo = require('../service/mongo.js');
var returnDataCtl = require('./makeReturnData');

var func5 = function(id){
return new Promise(function(resolve, reject) {
mysql.func1(id)
.then(function(data){
var result= {
"res1":[]
}
if(data.length == 0) {
resolve(result);
}
var promises = [];
for(var index = 0 ;index < data.length;index++){
var promise = mongo.func3(data[index].id);
promises.push(promise);
}
Promise.all(promises).then(function(re){
for(var index in re){
var tempdata = returnDataCtl.setupReturnData(data[index],re[index][0]);
result.res1.push(tempdata);
}
resolve(result);
});
})
.catch(function(err){
reject(err);
});
});
}

//func6もfunc5と同じですので省略します。
exports.func7 = function(id,res){
var func5 = func5(id);
var func6 = func6();
var promises = [func5,func6];
var result = {
"res1":[],
"res2":[]
}
Promise.all(promises).then(function(re){
result.res1 = re[0].res1;
result.res2 = re[1].res2;
res.json(result);
})
.catch(function(err){
console.log(err);
res.status(500).json({"code": 1, "status":"failed"});
});
}


終わりに

  これが正解だとは思いません。そもそもデザインを変えればこんなことをやらなくて済むかもしれません。どうしてもこんなデザインが必要となったときに参考になればと思います。