【问题标题】:Using ES6 Generator functions with SailsJS在 SailsJS 中使用 ES6 生成器函数
【发布时间】:2016-03-03 01:49:22
【问题描述】:

我喜欢 nodejs 中的生成器。它们帮助 nodejs 看起来更像服务器端代码。我正在尝试在我的 Sails 应用程序中使用生成器。这是我的控制器,当我访问“get /hi”时它可以工作:

/**
 * FooController
 *
 * @description :: Server-side logic for managing foos
 * @help        :: See http://sailsjs.org/#!/documentation/concepts/Controllers
 */

module.exports = {
  hi: function (req, res){
    return res.send("Hi there!");
  }
};

但是,当我将 hi 动作更改为生成器函数时...

module.exports = {
  hi: function* (req, res){
    return res.send("Hi there!");
  }
};

此操作永远不会返回响应。好像在等什么。如何在 SailsJS 控制器和实际上所有 Sails 中使用 ES6 生成器?

【问题讨论】:

  • 为什么您想这样做?现在你有了一个返回生成器的函数(这不是魔法!)而不是调用res.send的函数——当然它的行为不同。
  • 可以做到,只是你尝试过的有一点点变化,看看我下面的答案:)

标签: node.js sails.js ecmascript-6


【解决方案1】:

你可以使用它,事实上,如果我们都使用这种风格会很棒,它在你的代码中增加了很多可读性和灵活性(不再是回调地狱),但这不是使用它的方式

正如@Cohars 所说,sails 期望一个函数作为控制器操作,你不能像 Koa 那样传递一个生成器,但这并不妨碍你使用它们,问题是 生成器本身非常没用,您需要一个调用它并对其进行迭代的函数,我相信 koa 在框架级别为您做到了这一点,但您在库级别有一些可用的选项,例如 @987654321 @ 或 yortus/asyncawait/ 这是我使用的,因为作为函数实现的节点光纤比 es6 生成器更灵活(尽管它们几乎相同),我会在几秒钟内告诉你为什么。

所以这里是你如何使用它:

首先npm install co 并在您的控制器中使用它,或者将其作为全局添加到 config/bootstrap.js 中,因为您将经常使用它。完成后,您可以在控制器中使用它。

module.exports = {
  hi: function(req, res){
    co(function* (){
      // And you can use it with your models calls like this
      let user = yield User.findOne(req.param('id'))
      return res.send("Hi there" + user.name + "!");
    })
  }
};

就是这样

现在,如果您更愿意使用 async/await,它非常相似,如下所示:

module.exports = {
  hi: function(req, res){
    async(function(){
      // Since await is a function, you can access properties
      // of the returned values like this which is nice to
      // access object properties or array indices
      let userName = await(User.findOne(req.param('id'))).name
      return res.send("Hi there" + userName + "!");
    })();
  }
};

有一个警告,如果您通过this 调用控制器的其他方法,请记住,如果您使用 async/await,它们将引用生成器 fn 或传递的常规 fn,所以一定要保存它的上下文,或者因为你已经在使用 es6 语法,你可以使用带有 async/await 的胖箭头,不幸的是不能使用 co,因为没有胖箭头版本的生成器(..yet?)

所以它会是这样的:

module.exports = {
  hi: function(req, res){
    async(() => {
      let params = this._parseParams(req);
      let userName = await(User.findOne(params.id)).name
      return res.send("Hi there" + userName + "!");
    })();
  },
  _parseParams: function(req){
    let params = req.allParams()
    // Do some parsing here...
    return params
  }

};

几个月来我一直在使用第二种方法,并且效果很好,我也尝试过使用 co 并且效果也很好,我只是更喜欢 async/await 模块(并且应该更快一点) 如果您使用的是咖啡脚本,那么它是完美的匹配,因为您的 sintax 将类似于 do async => await User.find()

更新:

我创建了一个包装器,如果您使用 yortus async/await 或检查源代码并根据需要修改它以与 co 或其他东西一起使用,您可以使用它。

这里是链接 https://www.npmjs.com/package/async-handler,处于 alpha 阶段,但我正在自己的应用程序上使用,并且可以按预期工作,如果没有提交问题。

这样 las 的示例将如下所示:

module.exports = {
    hi: asyncHandler((req, res)->{
      let params = this._parseParams(req);
      let userName = await(User.findOne(params.id)).name
      return res.send("Hi there" + userName + "!");
    }),
    _parseParams: function(req){
      let params = req.allParams()
      // Do some parsing here...
      return params
    }
};

使用此处理程序,您可以获得额外的好处,即如果异步/承诺错误没有被 try/catch 捕获,则它们可以在帆上正确传播

【讨论】:

    【解决方案2】:

    Sails 在这里需要一个常规函数,而不是生成器。也许你可以看看co,但不确定它是否真的对 Sails 有帮助。如果你真的想使用生成器,你可能应该尝试Koa,它有基于它的several frameworks

    【讨论】:

    • 只是对此的更新:虽然 Sails 和 Waterline 不鼓励低级别使用 ES 生成器,但他们强烈鼓励使用 await。根据经验:“如果它支持 .exec(),那么它就是一个 Deferred,所以它还支持 await,+ 其他便利方法,如 .toPromise()、.intercept() 和 .tolerate()”(更多对此:npmjs.com/package/parley)
    【解决方案3】:

    我的做法是这样的:

    const Promise = require('bluebird');
    
    module.exports = {
      hi: Promise.coroutine(function* (req, res) {
        let id = req.params('id'),
            userName;
        try {
          userName = yield User.findOne(id).name;
        }
        catch (e) {
          sails.log.error(e);
          return res.serverError(e.message);
        }
    
        return res.ok(`Hi there ${userName}!`);
      })
    }
    

    效果很好。您只需要确保从控制器调用的任何函数都返回 Promise。

    【讨论】:

      【解决方案4】:

      将此代码放入您的bootstrap.js,一切都会像魅力一样发挥作用!

      var _ = require('lodash');
      var coExpress = require('co-express');
      
      sails.modules.loadControllers(function (err, modules) {
        if (err) {
          return callback(err);
        }
        sails.controllers = _.merge(sails.controllers, modules);
      
        // hacking every action of all controllers
        _.each(sails.controllers, function(controller, controllerId) {
          _.each(controller, function(action, actionId) {
            actionId = actionId.toLowerCase();
            console.log('hacking route:', controllerId, actionId);
            // co.wrap,generator => callback
            action = coExpress(action);
            sails.hooks.controllers.middleware[controllerId][actionId] = action;
          });
        });
        // reload routes
        sails.router.load(function () {
          // reload blueprints
          sails.hooks.blueprints.initialize(function () {
            sails.hooks.blueprints.extendControllerMiddleware();
            sails.hooks.blueprints.bindShadowRoutes();
            callback();
          });
        });
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2017-11-20
        • 2016-10-14
        • 2015-04-16
        • 2016-08-21
        • 2014-02-12
        • 2014-02-13
        • 2015-03-02
        • 2018-04-14
        相关资源
        最近更新 更多