无法确定将 Await 合并到异步函数中的位置

Posted

技术标签:

【中文标题】无法确定将 Await 合并到异步函数中的位置【英文标题】:Unable To Work Out Where To Incorporate The Await In Async Function 【发布时间】:2021-10-19 07:28:32 【问题描述】:

我有一组与图像相关的表单(每个表单都用于向从 mysql 数据库获取的相应图像添加详细信息)。后端使用 php 处理,但这些图像的详细信息使用 javascript Fetch API 发送到数据库。

我想要做的是在当前表单列表已提交并将相关数据添加到数据库(即没有更多图像要处理)时显示一个按钮以“上传更多图像”。

我正在使用 for of 循环,因此我可以使用 async/await,但我无法让它发挥作用。

在下面的代码中,我创建了processImageFormats() 函数async,但我无法弄清楚如何在item.remove()“await”之后创建 if 语句,直到 fetch() 发生?这是需要发生的正确事件顺序吗?

每次处理/提交到数据库的图像表单时,item.remove() 都会从文档中删除该表单元素。

我尝试查看Using async/await with a forEach loop 等问题,因此将其从forEach 循环更改为for of 循环,但无法弄清楚如何合并await 部分来解决手头的问题。

JavaScript

var imageForms = document.querySelectorAll('.image-upload-details-form');

var uploadMoreImages = document.querySelector('#upload-images-link');

async function processImageForms() 

    for (let item of imageForms) 
        
        item.addEventListener("submit", function (evt) 
        
            evt.preventDefault();

            const formData = new FormData(this);

            fetch("upload-details.php", 
                method: 'post',
                body: formData
            ).then(function(response)
                return response.text();
            ).then(function(text)
                console.log(text);
            ).catch(function (error)
                console.error(error);
            )

            item.remove();

            // ** show or hide 'upload more images' link when there are no more forms to process - the bit that isn't working **
            if (item.length === 0) 
                uploadMoreImages.style.display = 'inline-block';
            

        )

    
    


processImageForms();


// show or hide 'upload more images' link on pageload
if (imageForms.length === 0) 
    uploadMoreImages.style.display = 'inline-block';
 else 
    uploadMoreImages.style.display = 'none';

HTML

<a id="upload-images-link" href="upload.php">UPLOAD MORE IMAGES</a>

【问题讨论】:

你试过let response = await fetch("upload-details.php", method: 'post', body: formData); 吗? 【参考方案1】:

问题原来不是异步/等待 - 尽管得到答案很棒,因为它们帮助我理解了这个范例。

事实证明,我需要在 item.remove() 之后将 uploadMoreImages 变量重新分配给新变量 curImageForms

item.remove();

// update imageForms variable
var curImageForms = document.querySelectorAll('.image-upload-details-form')

// show or hide 'upload more images' link on pageload
if (curImageForms.length === 0) 
    uploadMoreImages.style.display = 'inline-block';

uploadMoreImages 仍在使用在提取之前分配的 .length 属性。

【讨论】:

【参考方案2】:

使事件处理函数成为async 函数,然后await 调用fetchres.text

item.addEventListener("submit", async function (evt) 
                             /* ^^^^^  make the event handler async */
     ...

     try 
        const response = await fetch("upload-details.php", 
            method: 'post',
            body: formData
        );

        const data = await response.text();
      catch (error) 
        // handle error
     

     ...
)

事件处理程序必须是 async,因为这是您将在其中使用 await 关键字的函数。

processImageForms 可以是非异步函数,因为您没有直接在其中使用 await 关键字。


注意:我会考虑利用event bubbling 并在公共父元素上添加一个 single 事件处理程序,而不是为每个项目添加单独的事件侦听器所有项目。

【讨论】:

【参考方案3】:

在这种情况下,使用for 循环能够await 并不是一个问题,因为无论循环结构如何,您仍然在回调函数内部:

item.addEventListener("submit", function (evt) 

await函数中的任何东西首先需要是async

item.addEventListener("submit", async function (evt) 

整个链解析为Promise

fetch("upload-details.php", 
    method: 'post',
    body: formData
).then(function(response)
    return response.text();
).then(function(text)
    console.log(text);
).catch(function (error)
    console.error(error);
);

你可以await整个事情:

await fetch("upload-details.php", 
    method: 'post',
    body: formData
).then(function(response)
    return response.text();
).then(function(text)
    console.log(text);
).catch(function (error)
    console.error(error);
);

虽然我认为它对await 的每一步都更干净、更一致。包括catch,整个事情可能是这样的:

try 
    let response = await fetch("upload-details.php", 
        method: 'post',
        body: formData
    );
    let text = await response.text();
    console.log(text);
 catch (error) 
    console.error(error);

【讨论】:

嗨@David。它仍然无法正常工作,但我想知道我是否需要对 item.length === 0 代码块做一些事情,现在它被包装在异步函数中? @paul_cambs:你不应该这样做,比较操作不是异步的。具体是什么不起作用? 处理完所有图像后,按钮不会出现(除非页面被引用)。不过,我在控制台中没有收到任何错误。

以上是关于无法确定将 Await 合并到异步函数中的位置的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法将等待/异步 try/catch 块包装到每个函数?

Sir, 这个年代了, 异步编程确定不了解一下?

是否可以将私有子合并到 VBA 访问中的函数中?

Flutter 如何处理异步/等待中的错误

Typescript async/await 无法确定正确的返回类型

如何将n个excel表格合并在同一份excel中的同一表格中,他们的表头都一样