【问题标题】:Serverless framework can't use promise?无服务器框架不能使用promise?
【发布时间】:2021-03-12 17:05:24
【问题描述】:

我正在尝试使用无服务器框架制作 REST api。

有些函数是异步的。

所以我使用Promise

但是承诺不起作用(没有响应)

所以,我使用了await 关键字。它工作正常。

我认为这是不好的方式。如何在 serverless 框架中使用 Promise?

任何意见或建议将不胜感激。提前谢谢你。

【问题讨论】:

  • 想一想:何时(及时)终止请求并返回响应?承诺何时解决?有没有其他方法可以等待响应的返回,直到承诺得到解决?你最好的选择是等待。为什么会这样不好?
  • @ZorgoZ 感谢反馈。我认为await 有性能问题。假设,有一个非常havy。用户总是等待这个工作。正确的 ?所以我不希望它用户等待..
  • 问题缺少stackoverflow.com/help/mcve。目前还不清楚问题是什么。 async..await 是原始承诺的语法糖。
  • 不,await 不是性能问题,更是一种收获。是的,它是一种语法糖,但这种情况下的替代语法就像地狱一样:您仍然需要阻止 api 方法 - 而 js 没有用于此的工具。 Webapis(例如在 c# 中)从几年前就开始异步了。如果你认为 promise 需要很长时间才能完成,那么 webapi 并不是最好的设计选择:你可以使用 websocket。然后,调用将只是开始执行后端操作的指令。当你有响应时,它可以被推送。
  • 你使用了错误的 Promise。请出示您的代码,以便我们找出问题所在。

标签: node.js typescript serverless-framework


【解决方案1】:

您可以通过多种方式使用 Promise。就个人而言,在另一个函数中分离承诺。

我用请求模块做了一个例子:

const request = require("request");

// The promise
const requestPromise = (url, options) =>
    new Promise((resolve, reject) => {
        options = options || {};
        const processRequest = (err, response) => (err ? reject(err) : resolve(response));
        request(url, options, processRequest);
    });


// You can use like this
module.exports = (event,context)  => {
    let url = event.url;
    requestPromise(url)
        .then(response => {
            // Do something
            context.succeed({succeed: true /* put return data here */})
        })
        .catch(details => context.fail({error: true, details: details}));
}

// Or this
module.exports = async (event,context)  => {
    try {
        let url = event.url;
        let response = await requestPromise(url);
        // Do something
        context.succeed({succeed: true /* put return data here */});
    } catch (details) {
        context.fail({error: true, details: details});
    }
}

如果你使用 async/wait,你需要添加 try/catch 来处理错误。

【讨论】:

    【解决方案2】:

    我现在正在为 mysql 世界数据库编写一个 serverless-kubeless api。我昨天不得不解决这个问题。我得出了以下解决方案。它的功能不完整。但你没有要求那个。所以这是一个有效的 GET 端点,它接受各种查询参数来自定义查询。

    'use strict';
    
    const pool = require('./database');
    
    module.exports.handler = async (event, context) => new Promise((resolve, reject) => {
        let request = event.extensions.request;
        let response = event.extensions.response;
    
        try{
            let handleResults = (err, results, fields) => {
                if(err){
                    response.status(500).send({
                        success: false,
                        message: err.message,
                    });
                }else{
                    response.status(200).send({
                        success: true,
                        count: results.length,
                        data: results,
                    });
                }
            }
    
            if(typeof(request.query.id) !== "undefined"){
                // search for a specific region by id
                if (Number.isNaN(Number(request.query.id))) {
                    response.status(500).send({
                        success: false,
                        message: "id query param was not a number",
                    });
                }
    
                pool.query("select id,name,code,country_id from regions where id = ?", [request.query.id], handleResults);
            }else if(typeof(request.query.country) !== "undefined"){
                // search for a region list from a specific country
                if (Number.isNaN(Number(request.query.country))) {
                    response.status(500).send({
                        success: false,
                        message: "country query param was not a number",
                    });
                }
    
                pool.query("select id,name,code,country_id from regions where country_id = ?", [request.query.country], handleResults);
            }else{
                response.status(400).send({
                    success: false,
                    message: "Could not find country, or region query parameter. Require a search term"
                });
            }
        }catch(exception){
            response.status(500).send({
                success: false,
                message: exception.message
            });
        }
    });
    

    和database.js:

    const mysql = require("mysql");
    const util = require('util');
    
    const pool = mysql.createPool({
        connectionLimit: 10,
    
        host: process.env.DATABASE_HOSTNAME,
        user: process.env.DATABASE_USERNAME,
        port: process.env.DATABASE_PORT,
        password: process.env.DATABASE_PASSWORD,
        database: process.env.DATABASE_NAME,
    });
    
    pool.getConnection((err, connection) => {
        if (err) {
            if (err.code === 'PROTOCOL_CONNECTION_LOST') {
                console.error('Database connection was closed.');
            }
            if (err.code === 'ER_CON_COUNT_ERROR') {
                console.error('Database has too many connections.');
            }
            if (err.code === 'ECONNREFUSED') {
                console.error('Database connection was refused.');
            }
        }
    
        if (connection) connection.release();
    
        return;
    });
    
    // Magic happens here.
    pool.query = util.promisify(pool.query);
    
    module.exports = pool;
    

    【讨论】:

    • 一个评论和一个问题。问题 - 你永远不会在处理程序中返回承诺 - 它是如何工作的?评论 - 你永远不应该,我的意思是永远不要编写返回 500 的代码。这意味着“服务器错误”,这意味着服务器内部出现了问题(未处理的异常、内存不足等),就像非常糟糕的事情一样。以上两个 500 都是由于客户端传递了不正确的数据 - I.E.客户端错误 = 400。负载均衡器的默认行为通常是杀死返回 500 秒的服务器,但这是无服务器的...... - 所以它可能没什么大不了的。
    • 关于 500 的,是的,关于承诺,我可能应该改变它。这会将处理程序设置为一个异步函数,该函数在调用时返回 new Promise(...)
    【解决方案3】:

    我通常在我的无服务器项目中使用 Promises:

    //this would me in a module like: services/myhttpservice.js (for example)
    
    //wrap the GET HTTP request in a Promise
    module.exports.GetUrlPromise = function(url, cookie_session_value) {
        console.log(new Date().getTime() + " GetUrlPromise() CALLED: " + url);
        var j = request.jar();
    
        if(cookie_session_value){
             var cookie1 = request.cookie(cookie_name + '=' + cookie_session_value);
             j.setCookie(cookie1, cookie_domain);// domain used by the cookie, maybe make more generic?
        }
    
        // create the "Basic" auth header
        var auth = "Basic " + Buffer.from(basic_username + ":" + basic_password).toString("base64");
    
        //create request options
        var options = {
            'method': 'GET',
            'url': url, 
            'jar': j,
            'headers': {
            'Authorization': auth,// set Basic auth header that is the base64 of the un:pw combo
            'Content-Type': 'application/json'
        }
    };
    
    return new Promise((resolve, reject) => {
        request(options, function (error, response, body) {
            if(error){
                console.log('error:', error);   
                reject(error);      
            }else{
                console.log('statusCode:', response && response.statusCode); 
    
                // object for returning response results
                var http_resp = {};
                http_resp._session = GetCookieValue(response);
                http_resp.body = body;
                http_resp.statusCode = response.statusCode;
                //http_resp.response = response;
                http_resp.requestType = 'GET';
    
                console.log(JSON.stringify(http_resp));
                resolve(http_resp);         
            }
        });
    });
    

    }

    它使我能够轻松地对我的服务进行承诺调用:

     //in my controller code:
    
        myhttpservice.GetUrlPromise(page_url, user_session)
        .then((http_resp)=>{ etc...
    

    【讨论】:

      【解决方案4】:

      如果使用得当,Await 和 async 并不是坏习惯。 如果您没有相互依赖的承诺,您可以通过将所有承诺(不带等待)添加到数组中来“并行”调用它们,并使用 const responses = await Promise.all(promisesArray) 等待所有响应成功。

      有关更多信息,请参阅此答案,该答案很好地解释了Call async/await functions in parallel

      【讨论】:

        猜你喜欢
        • 2018-02-05
        • 2020-09-25
        • 1970-01-01
        • 2022-06-22
        • 2021-11-25
        • 1970-01-01
        • 2022-12-09
        • 2017-09-30
        • 2021-02-10
        相关资源
        最近更新 更多