nodejs+express一个很经典的问题--异步获取数据模板渲染

113 篇文章 0 订阅
40 篇文章 0 订阅

前言

很多时候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);
        });

    });
});

原理是加入多个任务队列,然后最后才执行最后的方法。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值