nodejs+express 1つのとても経典的な問題--非同期取得データテンプレートレンダリング
前言
多くの場合、nodejsはいくつかの非同期的な操作があります.例えば、ファイルを読んで書きます.例えば、httprequestを使ってバックグラウンドのデータを取得してレンダリングしますが、nodejsの特性のため、多くの場合は非同期です.どのように解決しますか?
問題コード
ソリューション
つの比較的に実行可能な方法はdeffered、promise方案を使うので、もちろん、requestはこれもdeffered promiseでカプセル化する必要があって、さもなくば死人を書きます.以下はプロジェクトに適用される成熟したプログラムコードの一部です.
多くの場合、nodejsはいくつかの非同期的な操作があります.例えば、ファイルを読んで書きます.例えば、httprequestを使ってバックグラウンドのデータを取得してレンダリングしますが、nodejsの特性のため、多くの場合は非同期です.どのように解決しますか?
問題コード
/**
* api。
*
*/
var request = require('request');
var Settings=require('../settings.js');
var fs = require('fs');
var sysUtil = require('../util/SystemUtil.js');
var logger=sysUtil.Logger;
exports.getMenuList=function(callback){
logger.info(" url:"+Settings.WebApi.ApiHost+Settings.WebApi.IndexMenuApi);
var _url=Settings.WebApi.ApiHost+Settings.WebApi.IndexMenuApi;
//_url="http://www.baidu.com";
request(_url, function (error, response, body) {
if (!error && response.statusCode == 200) {
if(callback){
callback(response,body);
}
}
else{
console.log(" 。");
}
}).pipe(fs.createWriteStream('./test/file1.txt'));
};
var express = require('express');
var router = express.Router();
var Settings=require("../settings");
var sysUtil=require("../util/SystemUtil.js");
var logger=sysUtil.Logger;
var fs=require("fs");
/* GET home page. */
router.get('/', function(req, res, next) {
//console.log("================");
//console.log(Settings);
//-- 。
var CategoryService=require("../service/CategoryService.js");
var _menuList={};
CategoryService.getMenuList(function(res1,body1){
_menuList=JSON.parse(body1);
//fs.writeFile("./test/file1.txt",JSON.stringify(_menuList),function(){});
});
res.render('index', { title: 'Express' ,menuList:_menuList});
});
module.exports = router;
ok、私達はテンプレートをレンダリングする時、menuListは永遠に空です....ソリューション
つの比較的に実行可能な方法はdeffered、promise方案を使うので、もちろん、requestはこれもdeffered promiseでカプセル化する必要があって、さもなくば死人を書きます.以下はプロジェクトに適用される成熟したプログラムコードの一部です.
/**
* request , , promise 。
*/
var logger = require('../util/logHelper.js').Logger;
var fs=require("fs");
var Q = require('q');
var util=require("../util/util.js");
var request = require('request');
var Extend=require("util")._extend;
var RequestHelper=function(){
this.taskList=[];
};
RequestHelper.prototype.addTask=function(_opt){
this.taskList.push(_opt);
}
RequestHelper.prototype.request=function(_opts){
var _deferred= Q.defer();
var _i_settings={
url:""
,method:"get"
,data:{}
,dataType:"json"
,error:function(error){
}
,success:function(sdata){
}
};
_i_settings=Extend(_i_settings,_opts);
if(_i_settings.method.toLocaleLowerCase()=="get"){
var _realUrl=util.Json2URL(_i_settings.url,_i_settings.data);
logger.info(_realUrl);
var req2=request(_realUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
var _res=body;
try{
if(_i_settings.dataType=="json"){
_res=JSON.parse(_res);
}
}
catch (ex){
var _error_msg="nodejs can not trans this data to JSON format: "+body;
logger.error("json translate error:"+_i_settings.url);
logger.error(_error_msg);
logger.error(body);
_deferred.reject(_error_msg);
return;
}
_deferred.resolve(_res);}
else{
var _error_msg="request helper error: can not request url:"+_realUrl+"";
logger.error(_error_msg);
logger.error(body);
_deferred.reject(error);
}
});
}
else{
//--post 。
request.post({
url:_i_settings.url
,form:_i_settings.data
},function(err,response,body){
if (!err && response.statusCode == 200) {
var _res=body;
try{
if(_i_settings.dataType.toLocaleLowerCase()=="json"){
_res=JSON.parse(_res);
}
}
catch (ex){
var _error_msg="nodejs can not trans this data to JSON format: "+body;
logger.error("json translate error:"+_i_settings.url);
logger.error(_error_msg);
logger.error(body);
_deferred.reject(_error_msg);
return;
}
_deferred.resolve(_res);}
else{
var _error_msg="request helper error: can not request url:"+_i_settings.url+"";
logger.error(_error_msg);
logger.error(err);
logger.error(body);
_deferred.reject(err);
}
});
}
var _promise= _deferred.promise;
_promise.then(_i_settings.success,_i_settings.error);
return _promise;
};
RequestHelper.prototype.run=function(onDone){
var me=this;
var taskList=this.taskList;
if(taskList.length<=0){
if(onDone){
onDone();
}
return;
}
var _now_taskReq=[];
for(var i=0;i< this.taskList.length;i++){
var _taskItem={
url:""
,success:function(parameter){
}
,error:function(parameter){
}
,method:"get"
,data:{}
,dataType:"json"
};
Extend(_taskItem,this.taskList[i]);
var _promise=me.request(_taskItem);
_now_taskReq.push(_promise);
}
//-- 。
if(_now_taskReq.length<=0){
var _warning_msg="request helper warning:task list has less than 1 task,do not send any request now.";
logger.warn(_warning_msg);
if(onDone){
onDone();
}
return;
}
Q.all(_now_taskReq)
.spread(function(){}).done(function(){
if(onDone){
onDone();
}
});
};
module.exports=RequestHelper;
どう使いますか//
router.get('/recommend',function(req,res,next){
GlobalService.getCommonPageData(req,function(commonData){
//res.send(JSON.stringify(commonData));
var pageData={
list:[]
,ads:[]
};
var ajaxHelper=new RequestHepler();
ajaxHelper.addTask({
url:ServerConf.ApiHost+Settings.WebApi.RecommendProductApi
,success:function(data){
var _json=data;
pageData.list=_json.rows;
}
,error:function(error){
logger.error(error);
}
});
ajaxHelper.addTask({
url:ServerConf.ApiHost+Settings.WebApi.RecommendProductAdApi
,success:function(data){
var _json=data;
pageData.ads=_json.rows;
}
,error:function(error){
logger.error(error);
}
});
ajaxHelper.run(function(){
commonData["pageData"]=pageData;
res.render('recommend', commonData);
});
});
});
原理は複数のタスクのキューに入れて、最後に最後の方法を実行することです.