【问题标题】:NodeJS Express API call structure asynchronous eventsNodeJS Express API 调用结构异步事件
【发布时间】:2021-09-10 03:35:53
【问题描述】:

我正在用 NodeJS 和 Express 做一个爱好项目,但是处理异步调用让我不知所措。我遇到了一个我想在社区中反弹的错误。

我目前使用 Express 进行此布局,我将向其发送帖子请求。

快递(后端)

app.post("/", async (req, res) => {
    const createDocument = (args1) => {

        // declare some variables ...
        // for loop ...
        // (quite fast)

        loadFile(args2, async () => {

            // upload a file (quite slow)
            await upload(file, filePath)

            //send post request to third party (quite fast)
            let res = await axios.post(url, data, {
                headers: {
                    'X-Auth-Token': KEY
                }
            }).then(res => console.log('success')).catch(error => console.log('failure'))
        })
    }

    const args1 = "someargs"

    await new Promise(resolve => setTimeout(resolve, 2000))
    await createDocument(args1)

    res.end()
})

反应(前端)

const saveDocButtonClicked = useCallback(async (event) => {

    // do some stuff ...

    await axios.post('/', {
        headers: {
            'Content-Type': 'application/json'
        },
        jsonData
    }).then(res => console.log('Data sent')).catch(err => console.log(err.data))

    // do some other stuff ...

}

我希望 React 应用等待,在从 API 调用到 Express 后端得到正确响应之前不要继续。

我希望 Express 应用仅在完成所有任务后才能给出正确的响应。

到目前为止,这对于较小的文件效果很好,但随着文件大小的增加,它们不再被保存/存储在数据库中。

我注意到的关键区别在于,在这些糟糕的情况下,字符串 successfailure 应该来自 Express 后端的这段代码; .then(res => console.log('success')).catch(error => console.log('failure')) 不再被输出。所以在某个地方,异步事件可能会抢先一步。

我确信我犯了很多错误,请随时指出,我很想学习这个,我是异步调用的大一新生。

【问题讨论】:

  • 我认为问题在于createDocument,您应该从该函数返回承诺,只要loadFile 完成,该函数就会解决。希望有帮助
  • 好的,这在代码中会是什么样子?我有几个想法,但不能写在cmets小窗口里。

标签: javascript node.js api express asynchronous


【解决方案1】:

您的代码在语法上似乎是正确的(尽管遵循一些 async/await 最佳实践可能会更好 - 但这些不应影响您的应用程序的逻辑)。您能否提供一些示例输入、输出和您的预期输出,以便我更好地理解问题?

同时,我认为可能只是upload() 功能很慢,尤其是对于较大的文件,所以您只需要等待更多时间才能记录“成功”或“失败”

编辑:我想出了一些与异步/等待流程不同的回调流程。似乎 createDocument 没有等待,或者知道等待 loadFile 完成,因为 loadFile 的东西被“隐藏”在回调后面。所以我改变了 createDocument 来返回一个 Promise:

app.post("/", async (req, res) => {
    const createDocument = (args1) => {
        // Return a promise that waits for loadFile
        return new Promise((resolve, reject) => {
            // declare some variables ...
            // for loop ...
            // (quite fast)

            loadFile(args, () => {
                // I dont like using async with callback, so I'mma use .then()
                function makeAxiosRequest() {
                    return axios.post(url, data, {
                        headers: {
                            "X-Auth-Token": KEY,
                        },
                    });
                }
                // Only resolve createDocument after loadFile's stuff is finished
                upload(file, filePath)
                    .then(() => makeAxiosRequest())
                    .then(() => console.log("Success"))
                    .catch((err) => console.log("Failure"))
                    .finally(resolve());
            });
        });
    };

    const args1 = "someargs";

    await new Promise((resolve) => setTimeout(resolve, 2000));

    await createDocument(args1);

    // I like sending something to frontend for better debug experience
    return res.json({ message: "Respond now ends" });
});

【讨论】:

  • 嘿,我可以使用一些示例输入和输出对原始问题进行编辑。然而奇怪的是,“成功”或“失败”从未被输出,即使在几个小时之后。
  • 我认为您定义 loadFile 函数的方式可能有问题。它看起来既异步又同时使用回调。如果您进行编辑,您能否包含一些有关如何定义 loadFile 函数的详细信息?
  • 该函数实际上不是我定义的,而是我正在使用的包的内置函数,本质上我是用一个长的base64字符串输入它,当它完全加载时,它会触发回调。
  • 我想出了一些与异步/等待流程不同的回调流程。似乎 createDocument 没有等待,或者知道等待 loadFile 完成,因为 loadFile 的东西被“隐藏”在回调后面。你能检查我的编辑看看它是否有效吗?
  • 嘿宝,我一定会检查
【解决方案2】:

从 createDocument 返回承诺将允许 await createDocument(args1) 等到它完成执行

app.post("/", async (req, res) => {
const createDocument = (args1) => {
    return new Promise((resolve,reject)=>{
        // declare some variables ...
        // for loop ...
        // (quite fast)

        loadFile(args2, async () => {

            // upload a file (quite slow)
            await upload(file, filePath)

            //send post request to third party (quite fast)
            let res = await axios.post(url, data, {
                headers: {
                    'X-Auth-Token': KEY
                }
            }).then(res => console.log('success')).catch(error => console.log('failure'))
            resolve(res);
            //TODO:: Reject if some error occurs;
        })
    });
}

const args1 = "someargs"

await new Promise(resolve => setTimeout(resolve, 2000))
await createDocument(args1)

res.end()
})

【讨论】:

    【解决方案3】:

    使用 async-await 和 then/catch 是处理这类事情的坏方法。使用 await 你可以完成这项工作

    try {
      const response = await axios.post('/', {
          headers: {
            'Content-Type': 'application/json'
          },
          jsonData
      })
      // Here is your data after response completed
      const data  = response.json()
    } catch(err) {
      console.log(err)
    } 
    

    或者您可以删除 async/await 并简单地使用 then/catch

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-03-05
      • 2013-07-07
      • 2017-11-14
      • 2019-07-20
      • 2017-03-10
      • 2017-11-15
      • 1970-01-01
      相关资源
      最近更新 更多