Sails.js 控制器从 Promise 中获取数据

Posted

技术标签:

【中文标题】Sails.js 控制器从 Promise 中获取数据【英文标题】:sails.js controller get data from a promise 【发布时间】:2020-04-05 22:44:17 【问题描述】:

我正在尝试使用sails.js(使用node.js)。 我有一个控制器如下。 Thsi 控制器将 url 参数中传递的 ical url 解析为 ical_url 我正在尝试解析它并根据需要构建一个标准化的 json objetc。我有一个parse 函数 仅暴露在此控制器之外。使用 node-ical npm 包 (https://www.npmjs.com/package/node-ical) 解析ical内容。在ical.fromURL 方法中,我有一个回调函数,我使用它 初始化变量normalized_data 并在其中存储数据。我打算使用这些数据 并调用decorate 方法进行一些处理并取回json。请 查看以//>>>>>> 开头的行,根据我的意愿,我无法访问normalized_data 根据https://github.com/jens-maus/node-ical/blob/HEAD/index.js#L87 ical.fromURL 正在返回一个承诺 但我很难理解如何使用作为该承诺一部分的数据。 有人可以帮我在这个文件中进行所需的更改(特别是在parse 方法中) 满足我的期望?提前致谢。

/**
 * IcalsController
 */

const ical = require('node-ical');
const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat'];

function normalize(ev_obj) 
    return 
        "uid": ev_obj.uid,
        "start": ev_obj.start.toDateString(),
        "end": ev_obj.end.toDateString(),
        "start_ts": ev_obj.start,
        "end_ts": ev_obj.end,
        "user": ev_obj.organizer.val.split("mailto:")[1].split("@")[0], //TODO - use regex for extraction
        "summary": ev_obj.summary,
        "categories": ev_obj.categories,
        "all_day": (ev_obj["event-allday"] == "true")
    


function decorate(data) 
    //do something here and return a json object
    //return json_object;


module.exports = 
  parse: function (req, res) 
    if (req.param("ical_url") == undefined) 
        return res.status(400).send("ical_url is missing");
     

    ical.fromURL( //refer - https://github.com/jens-maus/node-ical/blob/HEAD/index.js#L87
        req.param("ical_url"),
        ,
        function (err, data) 
          let normalized_data = [];
            for (let k in data) 
              if (data.hasOwnProperty(k)) 
                if (data[k].type == 'VEVENT')      
                  normalized_data.push(normalize(data[k]));
                
              
            
          
        );

    //>>>>>> Here I want to call decorate function and pass normalized_data as parameter
    let result = decorate(normalized_data)
    return res.send(result);
  ,
;

【问题讨论】:

【参考方案1】:

问题在于没有考虑fromURL 方法的异步特性。

代码正在调用fromURL,这将导致在将来某个时间方法完成时调用回调,然后立即尝试将尚未收到的数据作为响应发送给客户端。

您需要在异步操作完成并且您实际上已经收到一些数据后发送响应,更像这样:

parse: function (req, res) 
    if (req.param("ical_url") == undefined) 
        return res.status(400).send("ical_url is missing");
     

    ical.fromURL( //refer - https://github.com/jens-maus/node-ical/blob/HEAD/index.js#L87
        req.param("ical_url"),
        ,
        function (err, data) 
          let normalized_data = [];
            for (let k in data) 
              if (data.hasOwnProperty(k)) 
                if (data[k].type == 'VEVENT')      
                  normalized_data.push(normalize(data[k]));
                
              
            
           res.send(decorate(normalized_data)); << Response moved inside the callback.
          
        );
  

虽然我实际上建议您使用 async/await 关键字作为更简洁的解决方案。

parse: async function (req, res)  << Mark method as async
    if (req.param("ical_url") == undefined) 
        return res.status(400).send("ical_url is missing");
     
    // Await keyword lets us use data from a promise more like it were simpler synchronous code
    const raw_data= await ical.fromURL( //refer - https://github.com/jens-maus/node-ical/blob/HEAD/index.js#L87
        req.param("ical_url"),
        ); 
    let normalized_data = [];
    // Do your normalization of raw_data here
    return res.send(decorate(noramlized_data));

【讨论】:

谢谢。我选择了推荐的解决方案。使用异步/等待

以上是关于Sails.js 控制器从 Promise 中获取数据的主要内容,如果未能解决你的问题,请参考以下文章

Sails.js 将数据从部分控制器发送到部分视图

sails.js 从视图中的配置获取环境值

sails.js 从控制器方法访问控制器方法

Sails.js + Passport.js 获取当前登录用户

Sails.js 创建索引(根)控制器

Sails.js 政策不适用于单个控制器