代码之家  ›  专栏  ›  技术社区  ›  PeakGen

为什么循环中的'async'函数不能正常工作?

  •  -1
  • PeakGen  · 技术社区  · 5 年前

    const mysql = require('mysql2');
    const errorCodes = require('source/error-codes');
    const PropertiesReader = require('properties-reader');
    
    const prop = PropertiesReader('properties.properties');
    
    const con = mysql.createConnection({
        host: prop.get('server.host'),
        user: prop.get("server.username"),
        password: prop.get("server.password"),
        port: prop.get("server.port"),
        database: prop.get("server.dbname")
    });
    
    
    exports.deleteSellerPortfolioItemImages = async (event, context, callback) => {
    
        context.callbackWaitsForEmptyEventLoop = false;
    
        if (event.body == null && event.body == undefined) {
            var response = errorCodes.missing_parameters;
            callback(null, response)
        }
        else {
            let body = JSON.parse(event.body)
            let response="";
            //console.log("body", body);
    
            for(let i=0;i<body.length;i++)
            {
                
                let idseller_portfolio_item_images = Number(body[i].idseller_portfolio_item_images);   
                console.log(idseller_portfolio_item_images);  
    
                if (isNaN(idseller_portfolio_item_images)) {
                    response = errorCodes.invalid_parameter;
                    callback(null, response);
                }
                else {
                    // allows for using callbacks as finish/error-handlers
                    const sql = "DELETE FROM seller_portfolio_item_images WHERE idseller_portfolio_item_images = ? ";
                    await con.execute(sql, [idseller_portfolio_item_images], function (err, result) {
                        if (err) {
                            console.log(err.toString());
    
                            if (err.toString().indexOf('cannot be null') >= 0) {
                                response = errorCodes.not_null_parameters;
                                callback(null, response);
                            }
                            response = errorCodes.internal_server_error;
                            callback(null, response);
    
                        }
                        else {
                            response = {
                                "statusCode": 200,
                                "headers": {
                                    "Content-Type": "application/json"
                                },
                                "body": JSON.stringify({ status: 1 }),
                                "isBase64Encoded": false
                            };
                            
                        }
                    });
                }
            }
            //If there is no error, this response will be sent back after the for loop
            callback(null, response);
        }
    };
    

    然而,这只是返回一个空响应,没有记录被删除。

    但是如果我删除 callback(null, response); for 循环,记录将被删除。在这种情况下,将返回一个错误,因为没有 callback .

    我认为这是因为我的代码没有等待for循环完成,而是等待 回拨 .

    我也试过这样做,如下所示。

    const mysql = require('mysql2');
    const errorCodes = require('source/error-codes');
    const PropertiesReader = require('properties-reader');
    
    const prop = PropertiesReader('properties.properties');
    
    const con = mysql.createConnection({
        host: prop.get('server.host'),
        user: prop.get("server.username"),
        password: prop.get("server.password"),
        port: prop.get("server.port"),
        database: prop.get("server.dbname")
    });
    
    
    exports.deleteSellerPortfolioItemImages =  (event, context, callback) => {
    
        context.callbackWaitsForEmptyEventLoop = false;
    
        if (event.body == null && event.body == undefined) {
            var response = errorCodes.missing_parameters;
            callback(null, response)
        }
        else {
            let body = JSON.parse(event.body)
            let response="";
    
            body.forEach(async (element, index)=>{
                let idseller_portfolio_item_images = Number(element.idseller_portfolio_item_images);   
                console.log(idseller_portfolio_item_images);  
    
                if (isNaN(idseller_portfolio_item_images)) {
                    response = errorCodes.invalid_parameter;
                    callback(null, response);
                }
                else {
                    // allows for using callbacks as finish/error-handlers
                    const sql = "DELETE FROM seller_portfolio_item_images WHERE idseller_portfolio_item_images = ? ";
                    await con.execute(sql, [idseller_portfolio_item_images], function (err, result) {
                        if (err) {
                            console.log(err.toString());
    
                            if (err.toString().indexOf('cannot be null') >= 0) {
                                response = errorCodes.not_null_parameters;
                                callback(null, response);
                            }
                            response = errorCodes.internal_server_error;
                            callback(null, response);
    
                        }
                        else {
                            response = {
                                "statusCode": 200,
                                "headers": {
                                    "Content-Type": "application/json"
                                },
                                "body": JSON.stringify({ status: 1 }),
                                "isBase64Encoded": false
                            };
                            
                        }
                    });
                }
            })
            callback(null, response);
        }
    };
    

    这也给出了与上述相同的结果。

    为什么是我的 async 电话不通?

    1 回复  |  直到 5 年前
        1
  •  -1
  •   Josnidhin    5 年前

    默认情况下 mysql 模块函数基于回调,因此使用 async/await 行不通。见文件 here 关于如何使用基于承诺的函数。

    Mysql承诺示例

    const mysql = require('mysql2/promise');
    const con = mysql.createConnection({...});
    
    (async () => {
      try {
        const [rows, fields] = await connection.execute(...);
        // do something with result
      } catch (err) {
        // handle error
      }
    })();
    

    完成后,像这样更新处理程序函数签名,即忽略第三个参数。

    exports.handler =  async function(event, context)
    

    const mysql = require('mysql2/promise');
    
    exports.deleteSellerPortfolioItemImages = async (event, context) => {
        if (event.body) {
            return errorCodes.missing_parameters;
        }
       
        const body = JSON.parse(event.body);
        let images;
        
        try {
          images = validateData(body);
        } catch (err) {
          return errorCodes.invalid_parameter;
        }
        
        const sql = "DELETE FROM seller_portfolio_item_images WHERE idseller_portfolio_item_images = ? ";
        
        const promises = images.map(async (item) => {
          return con.execute(sql, [item]);
        });
    
        try {
          await Promise.all(promises);
        } catch (err){
          if (err.toString().indexOf('cannot be null') >= 0) {
            return errorCodes.not_null_parameters;
          }
          return errorCodes.internal_server_error;
        }
        
        return {
          'statusCode': 200,
          'headers': {
              'Content-Type': 'application/json'
          },
          'body': {
            status: 1
          },
          'isBase64Encoded': false
        };
    };
    
    /**
     *
     */
    function validateData (body) {
      // TODO: throw error on invalid data
      // otherwise return an array of idseller_portfolio_item_images
    }
    

    这个 forEach 函数为数组中的每个元素执行给定的函数(在本例中为异步函数),但它不等待异步函数结果。有多种方法可以解决此示例代码

    const promises = body.map(async () => {....});
    
    // using 'all' just for demo use appropriate function in your case
    await Promise.all(promises);
    

    选择2

    const promises = [];
    
    body.forEach(()=>{
      // add the promise promises array
      promises.push(...)
    });
    
    // using 'all' just for demo use appropriate function in your case
    await Promise.all(promises);
    

    附注2

    从aws lambda函数直接连接到Mysql DB是个坏主意。对于lambda函数的每次执行,它将创建到db的新连接。这会给数据库服务器带来不必要的负载,我建议您研究连接池。鉴于它是一个lambda函数,在函数中进行连接池是非常无用的。结账 AWS RDS Proxy