英文:
window.location.href cancels async calls to API
问题
以下是代码部分的翻译:
当代码运行时,window.location.href 在所有异步调用到API完成之前就会触发。如果我在位置上设置一个断点,它就能正常工作。
如何等待所有调用完成后再调用 window.location.href?
代码:
const saveInvoice = async () => {
if (containsItems()) {
let customerId = document.getElementById("Customer").value;
let date = document.getElementById("Date").value;
let dueDate = document.getElementById("DueDate").value;
let msgKID = document.getElementById("MSG").value;
let accountId = document.getElementById("Account").value;
let data = await WebRequest("InvoiceAPI", "CreateInvoiceAsync", null, { "CustomerId": customerId, "Date": date, "DueDate": dueDate, "MsgKID": msgKID, "AccountId": accountId });
getLineNumbers().forEach(async (nr) => {
let prodId = parseInt(document.querySelector('select.prod[data-id="' + nr + '"]').value);
let descr = document.querySelector('input.description[data-id="' + nr + '"]').value;
let price = parseFloat(document.querySelector('span.price[data-id="' + nr + '"] > span.sum').innerHTML);
let mva = parseInt(document.querySelector('span.mva[data-id="' + nr + '"] > span.sum').innerHTML);
let mvaSum = parseFloat(document.querySelector('input.mva-value[data-id="' + nr + '"]').value)
let count = parseInt(document.querySelector('input.count[data-id="' + nr + '"]').value);
let perc = parseInt(document.querySelector('input.perc[data-id="' + nr + '"]').value);
let sum = parseFloat(document.querySelector('#Lines > div.line.row > div.amount-wrap[data-id="' + nr + '"] span.line-sum').innerHTML);
await WebRequest("InvoiceAPI", "CreateInvoiceLineAsync", null, { "InvoiceId": data.json.id, "ProductId": prodId, "Description": descr, "Count": count, "Discount": perc, "Price": price, "Mva": mva, "MvaSum": mvaSum, "Sum": sum });
});
window.location.href = "View/" + data.json.uId;
}
else {
document.getElementById("InvoiceErrorWrap").classList.remove("hide");
}
};
英文:
When the code runs window.location.href kicks in before all async calls to the API is done. If I set a breakpoint on the location it works fine.
How can wait until all calls are done before invoking window.location.href?
Code:
const saveInvoice = async () => {
if (containsItems()) {
let customerId = document.getElementById("Customer").value;
let date = document.getElementById("Date").value;
let dueDate = document.getElementById("DueDate").value;
let msgKID = document.getElementById("MSG").value;
let accountId = document.getElementById("Account").value;
let data = await WebRequest("InvoiceAPI", "CreateInvoiceAsync", null, { "CustomerId": customerId, "Date": date, "DueDate": dueDate, "MsgKID": msgKID, "AccountId": accountId });
getLineNumbers().forEach(async (nr) => {
let prodId = parseInt(document.querySelector('select.prod[data-id=\"' + nr + '\"]').value);
let descr = document.querySelector('input.description[data-id=\"' + nr + '\"]').value;
let price = parseFloat(document.querySelector('span.price[data-id=\"' + nr + '\"] > span.sum').innerHTML);
let mva = parseInt(document.querySelector('span.mva[data-id=\"' + nr + '\"] > span.sum').innerHTML);
let mvaSum = parseFloat(document.querySelector('input.mva-value[data-id=\"' + nr + '\"]').value)
let count = parseInt(document.querySelector('input.count[data-id=\"' + nr + '\"]').value);
let perc = parseInt(document.querySelector('input.perc[data-id=\"' + nr + '\"]').value);
let sum = parseFloat(document.querySelector('#Lines > div.line.row > div.amount-wrap[data-id=\"' + nr + '\"] span.line-sum').innerHTML);
await WebRequest("InvoiceAPI", "CreateInvoiceLineAsync", null, { "InvoiceId": data.json.id, "ProductId": prodId, "Description": descr, "Count": count, "Discount": perc, "Price": price, "Mva": mva, "MvaSum": mvaSum, "Sum": sum });
});
window.location.href = "View/" + data.json.uId;
}
else {
document.getElementById("InvoiceErrorWrap").classList.remove("hide");
}
};
答案1
得分: 2
你可以使用 Promise.all
来等待一组 Promise
完成。(Array#forEach
不适用于处理 Promise
。)
在这里,我们可以使用 Array#map
来创建一个包含由 getLineNumbers()
返回的数组中每个元素的 Promise
的数组。
await Promise.all(getLineNumbers().map(async nr => {
// 其他代码...
await WebRequest("InvoiceAPI", "CreateInvoiceLineAsync", null, { "InvoiceId": data.json.id, "ProductId": prodId, "Description": descr, "Count": count, "Discount": perc, "Price": price, "Mva": mva, "MvaSum": mvaSum, "Sum": sum });
}));
// 设置位置在这里
英文:
You can use Promise.all
to wait for an array of Promise
s to be completed. (Array#forEach
is not designed to work with Promise
s.)
Here, we can use Array#map
to create an array containing a Promise
for each element in the array returned by getLineNumbers()
.
await Promise.all(getLineNumbers().map(async nr => {
// other code...
await WebRequest("InvoiceAPI", "CreateInvoiceLineAsync", null, { "InvoiceId": data.json.id, "ProductId": prodId, "Description": descr, "Count": count, "Discount": perc, "Price": price, "Mva": mva, "MvaSum": mvaSum, "Sum": sum });
}));
// set location here
答案2
得分: 0
每个单独的异步操作似乎在内部使用await
,但没有等待所有这些操作。更确切地说,saveInvoice
是异步的,但它不会等待任何东西。
你可以用调用.map()
来替代.forEach()
来返回这些承诺:
const promises = getLineNumbers().map(async (nr) => {
//...
});
然后等待这些承诺:
await Promise.all(promises);
window.location.href = "View/" + data.json.uId;
英文:
Each individual asynchronous operation appears to internally await
, but nothing is awaiting all of those operations. More literally, saveInvoice
is async
but it doesn't await
anything.
You can replace the call to .forEach()
with a call to .map()
to return the promises:
const promises = getLineNumbers().map(async (nr) => {
//...
});
Then await those promises:
await Promise.all(promises);
window.location.href = "View/" + data.json.uId;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论