Javascript node async/await不适用于我(当使用Postgres/node时-在转到下一个调用之前使用数据库更新)

Javascript node async/await不适用于我(当使用Postgres/node时-在转到下一个调用之前使用数据库更新),javascript,node.js,async-await,node-postgres,Javascript,Node.js,Async Await,Node Postgres,await在代码块更新db(使用postgres/node)时,未按预期进行阻塞。 我有一个异步函数调用的列表,每个调用都会创建一个数据库,随后的每个调用都会处理由上一个调用更新的数据 一行大约有八个调用,每个调用都必须更新正在处理的完整数据集,100%完成,然后再转到下一个 我试图使一切都不异步,但似乎由于我使用的库(postgres/node),我被迫使一切都异步/等待 在进行下一个函数调用之前,每个函数调用必须100%完成,因为下一步对字段不为null的行(上一步填充值的行)进行选择

await
在代码块更新db(使用postgres/node)时,未按预期进行阻塞。

我有一个异步函数调用的列表,每个调用都会创建一个数据库,随后的每个调用都会处理由上一个调用更新的数据

一行大约有八个调用,每个调用都必须更新正在处理的完整数据集,100%完成,然后再转到下一个

我试图使一切都不异步,但似乎由于我使用的库(postgres/node),我被迫使一切都异步/等待


在进行下一个函数调用之前,每个函数调用必须100%完成,因为下一步对字段不为null的行(上一步填充值的行)进行选择

我在每次通话前都有一个wait,它会做一些事情(参见下面的代码):

  • 从csv加载数据库
  • 下一步选择刚刚插入的所有行,调用API并更新数据库
  • 等等,
  • 但在某一点上,当下一个函数执行时,所有行都没有被更新(当我进行跟踪和验证时,SQL语句没有返回任何内容)

    代码似乎直接通过第二个函数调用,而不是阻塞、尊重
    wait
    ,并完成其代码块

    如果我注释掉后几行中的某些行(取决于前几行),并让程序运行到完成,则数据库将得到更新

    代码在功能上没有问题,一切都正常,只是从开始到完成都不正常

    在开始运行两个函数调用后,让它运行,然后我可以注释掉这些行,取消对流中后面的行的注释,然后再次运行,所有操作都按预期进行,但我无法在两个未注释的行都未注释的情况下运行到完成

    在进入下一步之前,如何确保每个函数调用都100%完成,数据库中的所有更新都已完成

    async/await对我不起作用

    这不是伪代码,而是实际代码,正在执行,我正在使用,只更改了函数名。这是真正的工作代码,直接从我的IDE剪切粘贴。

    // these are functions I call below (each in their own .js)
    const insert_rows_to_db_from_csv = require('./insert_rows_to_db_from_csv')
    const call_api_using_rows_from_function_above = require('./call_api_using_rows_from_function_above')
    const and_so_on = require('./and_so_on')
    const and_so_on_and_on = require('./and_so_on_and_on')
    const and_so_on_and_on_and_on = require('./and_so_on_and_on_and_on')
    
    // each of the above exports a main() function where I can call func.main() just // like this one defined below (this is my main() entry point)
    
    module.exports = {
        main: async function (csvFilePath) {
            console.log('service: upload.main()')
            try {
                const csvList = []
    
                let rstream = fs.createReadStream(csvFilePath)
                    .pipe(csv())
                    .on('data', (data) => csvList.push(data))
                    .on('end', async () => {
                        let num_rows = csvList.length
    
                        //step one (if I run these two, with step two calls below commented out, this works)
                        await insert_rows_to_db_from_csv.main(csvList);
                        await call_api_using_rows_from_function_above.main();
    
                        // step two
                        // blows up here, on the next function call,
                        // no rows selected in sql statements, must comment out, let the above run to
                        // completion, then comment out the rows above, and let these run separate
                        await work_with_rows_updated_in_previous_call_above.main();   // sets
                        await and_so_on.main();
                        await and_so_on_and_on.main();
                        await and_so_on_and_on_and_on.main();
                    })
            } catch (err) {
                console.log(err.stack)
            } finally {
            }
        }
    };
    
    下面是我用来调用DB的插入/更新的一行代码:

     return await pool.query(sql, values);
    
    就这样,没别的了。这是通过使用:

    npm安装页面


    第2部分-继续,

    我想问题可能就在这里。这就是我正在做的每一件事 API调用,然后插入(下一个函数调用依赖于此),这里有些代码的味道我无法分辨

    调用processBatch(batch),调用API,获取响应,然后在其中调用`handleResponseDetail(response),插入发生在这里。我想问题就在这里,如果有什么想法的话

    这是内部的一个代码块:
    wait call_api_使用上面的函数_中的_行_调用.main()

    它会在没有错误的情况下完成,插入行并提交,然后调用下一个函数,而下一个函数找不到行(在此处插入)。但是整个main().js上的wait会阻塞并等待,所以我不明白

    /**
     * API call, and within call handleResponse which does the DB insert.
     * @param batch
     * @returns {Promise<*>}
     */
    async function processBatch(batch) {
        console.log('Processing batch');
        return await client.send(batch).then(res => {
            return handleResponseDetail(res);
        }).catch(err => handleError(err));
    }
    
    // should this be async?
    function handleResponseDetail(response) {
    
        response.lookups.forEach(async function (lookup) {
    
            if (typeof lookup.result[0] == "undefined") {   // result[0] is Candidate #0
                ++lookup_fail;
                console.log('No response from API for this address.')
            } else {
                ++lookup_success;
    
                const id = await insert(lookup);
            }
        });
    }
    
    /**
    *API调用,并在调用handleResponse中插入DB。
    *@param批处理
    *@returns{Promise}
    */
    异步函数processBatch(批处理){
    console.log(“处理批”);
    返回等待客户端。发送(批处理)。然后(res=>{
    返回手柄响应详细信息(res);
    }).catch(err=>handleError(err));
    }
    //这应该是异步的吗?
    函数句柄响应详细信息(响应){
    response.lookups.forEach(异步函数(查找){
    如果(typeof lookup.result[0]=“undefined”){//result[0]是候选#0
    ++查找失败;
    console.log('此地址没有API响应')
    }否则{
    ++成功与否;
    const id=等待插入(查找);
    }
    });
    }
    
    您的
    主功能当前所做的只是创建流、分配侦听器并立即返回。它不会像你试图让它做的那样等待所有的听众去解决

    您需要将文件读取逻辑提取到另一个函数,该函数将返回仅在读取整个文件时才会解析的承诺,然后在
    main

    function getCsvList(csvFilePath) {
      return new Promise((resolve, reject) => {
        const csvList = []
        fs.createReadStream(csvFilePath)
          .pipe(csv())
          .on('data', (data) => csvList.push(data))
          .on('end', () => {
            resolve(csvList)
          })
          .on('error', (e) => reject(e))
      })
    }
    
    module.exports = {
      main: async function (csvFilePath) {
        try {
          const csvList = await getCsvList(csvFilePath)
          await insert_rows_to_db_from_csv.main(csvList);
          await call_api_using_rows_from_function_above.main();
          await work_with_rows_updated_in_previous_call_above.main();
          await and_so_on.main();
          await and_so_on_and_on.main();
          await and_so_on_and_on_and_on.main();
        } catch (err) {
          console.log(err.stack)
        } finally {
        }
      }
    };
    

    考虑到第2部分编辑中的代码块,问题现在很清楚了:所有
    insert()的
    都被安排在
    async/await
    代码其余部分的阻塞上下文之外!这是因为
    。有关详细信息,请参阅forEach

    我已经对您现有的代码进行了注释,以显示问题:

    function handleResponseDetail(response) { //synchronous function
    
        response.lookups.forEach(async function (lookup) { //asynchronous function
            //these async functions all get scheduled simultaneously
            //without waiting for the previous one to complete - that's why you can't use forEach like this
            if (typeof lookup.result[0] == "undefined") {   // result[0] is Candidate #0
                ++lookup_fail;
                console.log('No response from API for this address.')
            } else {
                ++lookup_success;
    
                const id = await insert(lookup); //this ONLY blocks the inner async function, not the outer `handleResponseDetail`
            }
        });
    }
    
    下面是该函数的一个固定版本,它应该可以像您期望的那样工作:

    async function handleResponseDetail(response) {
    
        for(const lookup of response.lookups) {
    
            if (typeof lookup.result[0] == "undefined") {   // result[0] is Candidate #0
                ++lookup_fail;
                console.log('No response from API for this address.')
            } else {
                ++lookup_success;
    
                const id = await insert(lookup); //blocks handleResponseDetail until done
            }
        }
    }
    
    或者,如果插入顺序无关紧要,您可以使用
    Promise.all
    提高效率:

    async function handleResponseDetail(response) {
    
        await Promise.all(response.lookups.map(async lookup => {
    
            if (typeof lookup.result[0] == "undefined") {   // result[0] is Candidate #0
                ++lookup_fail;
                console.log('No response from API for this address.')
            } else {
                ++lookup_success;
    
                const id = await insert(lookup);
            }
        })); //waits until all insertions have completed before returning
    }
    

    重申一下,您不能轻松地将
    .forEach()
    与async/await一起使用,因为
    .forEach()
    只是同步调用数组中每个元素的给定函数,而不考虑在调用下一个承诺之前等待每个承诺。如果您需要循环在每个元素之间阻塞,或者在从函数返回之前等待所有元素完成处理(这是您的用例),则需要使用不同的for循环,或者如上所述使用
    Promise.all()

    什么是
    cvsList
    ?请显示实际和真实的数据库调用,不是你的伪代码。如果您向我们展示实际的和真实的代码,我们只能将您所做的与实际的数据库API进行比较。您必须正确地使用
    等待
    ,它才能执行您想要的操作,如果没有看到真正的代码,我们无法看到您是否正确地使用它。我不知道w