英文:
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 Promises to be completed. (Array#forEach is not designed to work with Promises.)
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;
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论