首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Node.js将异步转换为承诺

Node.js将异步转换为承诺
EN

Stack Overflow用户
提问于 2015-08-10 20:50:16
回答 1查看 99关注 0票数 0

我有一个中间件函数,它访问一个api并返回一个ID,这是正确的,但是在它返回数据之前调用next。视图是在第一次没有数据的情况下呈现的。我更愿意把它包装在一个承诺,并更新视图时,它是可用的。实现这一目标的最佳方式是什么。我一直在用Q服务实现一些东西,但没有任何运气。

Server.js

代码语言:javascript
复制
var app        = express();
var guid       = require('./server/guid.js')(app);

app.use(guid.checkGUID);

guid.js

代码语言:javascript
复制
var express    = require('express');
var Q          = require('q');
var request    = require('request');
var uuid       = require('uuid');

module.exports = function(app){


var checkGUID = function(req, res, next) {
  if(!app.locals.guid){
    getGUID();
    next();
  }else{
    next();
  }
};

var getGUIDOptions = {
  options....
};

var getGUID = function(req,res, next) {
  request(getGUIDOptions, returnGUID);  
};

function returnGUID(error, response, body) {
  if (!error && response.statusCode == 200) {
    app.locals.guid = body.guid;
    return body.guid;
  }else{
    console.log(body);
  }
};

return {
        checkGUID: checkGUID
    } 
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-08-10 22:46:28

您不需要使用承诺,只需要为请求调用中间件next()回调。下面是我编写它的方式,请注意,我试图正确地处理所有预期的错误条件。

代码语言:javascript
复制
var util=require('util'),
    request = require('request');

module.exports = function(app) {

  /**
   * Assure we have an app-wide GUID
   * @param {object} req
   * @param {object} res
   * @param {function} next - callback to next stage in request processing
   */
  var assureGUID = function(req, res, next) {
    if(app.locals.guid){ // we already have one
      next();
      return;
    }
    getGUID(req, res, next);
  };

  /**
   * Retrieve a GUID for this app
   * @param {object} req
   * @param {object} res
   * @param {function} next - callback to next stage in request processing
   */
  var getGUID = function(req, res, next) {

    var getGUIDOptions = {
      //options....
    };

    request(getGUIDOptions, function(err,resp,body){
      if(err){
        next(err);
        return;
      }
      if(200 !== resp.statusCode){
        next(new Error('failed to retrieve GUID, status='+resp.statusCode));
        return;
      }
      if(!('object'===typeof body && 'string'===typeof body.guid && body.guid)){
        next(new Error('failed to retrieve GUID, resp: '+util.inspect(resp,{depth:null})));
        return;
      }

      app.locals.guid=body.guid;

      next();
    });
  };

  return {
    assureGUID: assureGUID
  }
};

本质上,当请求击中这个处理程序,并且我们已经有了这个应用程序的GUID时,我们按下(通过调用next())。如果我们还没有GUID,就会请求一个新的GUID,当我们拥有它时,就调用next()。

如果你一意孤行,我也很乐意附上这个解决方案。

更新

好的,这是承诺(原文如此)承诺版本。我(和其他许多人)更喜欢Petka的蓝鸟承诺实现,所以我将在这里使用它而不是Q,如果需要的话,您应该能够不费吹灰之力地将这段代码转换成。

代码语言:javascript
复制
// Promises version

var util=require('util'),
    Promise=require('bluebird'),
    request = Promise.promisifyAll(require('request')); // see note 1.

var assureGUID = function(req,res,next){

  if(app.locals.guid){ // we already have one
    next();
    return;
  }

  var getGUIDOptions = {
    //options....
  };

  request.get(getGUIDOptions) // see note 2.
      .catch(function(err){ // get request failed
        next(new Error('GET request for GUID failed:'+err));
      })
      .spread(function(resp,body){ // see note 3.
        // check for proper result
        if(200 !== resp.statusCode){
          throw new Error('failed to retrieve GUID, status='+resp.statusCode);
        }
        if(!('object'===typeof body && 'string'===typeof body.guid && body.guid)){
          throw new Error('failed to retrieve GUID, resp: '+util.inspect(resp,{depth:null}));
        }
        app.locals.guid=body.guid;
        next();
      })
      .catch(function(err){ // unexpected result
        next(err);
      });
};

几个注意事项:

  1. Promise.promisifyAll()将自动地将由request模块公开的所有函数转换为承诺,如果它们遵循标准的f(err,res)节点回调模式。
  2. 关于为什么我们需要使用蓝鸟而不是简单的request(),请参阅关于"promisification“的说明。
  3. 如果调用不支持f(err,res),则可以使用Promise.spread()“传播”基函数中的可用参数。因此,由于request.get()是通过三个arg调用的:err (由承诺消费)、resbody,因此我们需要将剩下的两个arg“扩展”到新的承诺回调中。

最后,虽然我还没有测试这段代码,但它应该可以工作。如果您有任何问题,请不要犹豫,补充进一步的意见。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31928907

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档