无法确定将 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
调用fetch
和res.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 块包装到每个函数?