首先,讓我用最簡單的術語列出我想做的事情:
我有一系列需要按特定順序呼叫的函式;該順序中的每個函式都有自己需要遵循的順序。
我當前的代碼,簡化:
async function LastModuleFunction() {
await FirstModuleFunction(); // Order:1
await SecondModuleFunction(); // Order: 2
// ...etc...
await EighthModuleFunction(); // Order: 8
setTimeout(GoToNextPage(), 2000); // Order 9
}
function GoToNextPage() {
// some script irrelevant to this question...
window.location.href = 'OtherPage.aspx'; // Order: LAST
}
lastModule.js
async function FirstModuleFunction() {
var obj = { item1: 0, item2: 0, item3: '' }; // you get the idea
FirstModuleDataSaveProcess();
async function FirstModuleDataSaveProcess() {
await FirstModuleDataFunction1(); // Order: 1A
await FirstModuleDataFunction2(); // Order: 1B
// I created a shared function for AJAX
PostDataAjax('AutoSave_ModuleData.asmx/AutoSave_FirstModule', obj, true); // Order: 1C
// The last parameter is just a boolean to tell the function if it should fire a "Saved!"
// message (via Toast) upon success.
}
}
firstModule.js
$('#btnSaveAndFinish').on('click', async function() {
$(this).prop('disabled', true);
$(this).html(waitSpinner); // just a bootstrap "please wait" animation here
LastModuleFunction();
});
模塊導航.js
順序必須遵循以下模式:1A -> 1B -> 1C -> 2A -> 2B -> ... -> LAST
序列中的每個函式必須等待前一個函式完成。
無聊的背景故事和背景關系:
我有一個帶有多個 UserControl 模塊 (ascx) 的 aspx 頁面。哪個 UC 和多少個 UC 取決于用戶和一天中的時間(它是一個會議記錄器應用程式,每天處理 4 種不同型別的會議)。
Each time the user navigates to the next module (they come in on a bootstrap carousel), a series of functions prepares the data and sends it to a WebService class (asmx) via AJAX (see firstModule.js above). We tell the user this "auto-saves" the data as they go (which it does).
On the last module, the "next" button is replaced by a "save and finish" button. When clicked, this button goes through EACH of the previous modules again*, saves ALL form data to the database through each AJAX function, and THEN location.href's to a different aspx page.
*The user is also able to skip ahead or back to a module, which doesn't trigger an "auto-save," so the app makes extra-sure all data is accounted for.
What's actually happening:
Most of the time, this works as intended. The functions fire in order, and the 2-second buffer I give LastModuleFunction() is enough time to have the data saved and ready for the next page before it redirects.
...But sometimes, it doesn't/isn't.
There are two significant tells that indicate something's not right:
In
FirstModuleFunction(), the WebService called in the AJAX updates a data row that holds the core information for that meeting; the "MeetingCompleted" column in that data row is changed from 'N' to 'Y'. The next page's code, atPage_Load, checks if this value is indeed a 'Y'; if not, it redirects back to the original page with a specific query string that tells me that the check failed. So it looks like, in some cases,FirstModuleFunction()doesn't complete before the redirect fires.When placing
console.log()calls before each function inLastModuleFunction(), they fire in the correct sequence on the console, each time I tested. However, when I place anotherconsole.loginsideFirstModuleFunction(), for example, the console shows a different story:
1st module hit
2nd module hit
3rd module hit
function inside 1st module hit <-- what the...?
4th module hit
[etc.]
console
I'm now starting to think that simply using await when calling async functions isn't getting the job done. I can't remember where I read it would be this simple, but it appears I either misunderstood or was misinformed, hm? Apparently I need to use Promises...is that correct? Problem is, I could never wrap my head around how to make promises work with this exact sequence structure I need. Can someone help me understand what kind of structure I should be using?
Note: most of these functions do not return any value; they simply act as routines.
uj5u.com熱心網友回復:
修復#1:保持順序(比我想象的要容易)
感謝 Dave 的幫助,我得以解決部分問題。如果一個函式是函式序列的一部分await,并且它有自己的子函式序列也使用await,則將 添加await到所有子函式中,否則下一個“父”函式將不會等待最后一個子函式結束。最后呼叫函式無關緊要;ifSecondModuleFunction()是一個await函式,那么PostDataAjax可能最終會等待它,除非它被賦予一個await,并且您的訂單可能會被取消。當我應用此修復程式時,控制臺每次都會給我一個完美的序列(1、1a、1b、1c、2、2a、2b、3、3a,...等)。
async function FirstModuleFunction() {
var obj = { item1: 0, item2: 0, item3: '' };
await FirstModuleDataSaveProcess(); // <--await added here
async function FirstModuleDataSaveProcess() {
await FirstModuleDataFunction1();
await FirstModuleDataFunction2();
await PostDataAjax('AutoSave_ModuleData.asmx/AutoSave_FirstModule', obj, true); // <--await added here
}
}
換句話說:當有疑問時,等待它。
修復 #2:等待 AJAX(更棘手)
我發現,更大的問題與我提到的那個錯誤有關——在頁面重定向之前,AJAX 沒有在后臺更新資料行服務器端(AJAX -> asmx 子例程)。我的所有功能都以完美的順序觸發,但是如果沒有正確等待 AJAX 回應客戶端的重定向,這些都不重要。
有時setTimeout(在我的情況下,2 秒)給了它足夠的時間;有時它不會。我假設如果我添加await到$.ajax呼叫本身,我只是讓腳本等待帖子,而不是來自服務器的回應。事實證明我是對的。
在這種情況下,解決方案最終是兩個流行的“讓腳本等待”解決方案的組合。一個是,當然,await。另一種是添加回呼:
async function PostDataAjax(subdir, dataObj, showSuccess) {
// Toast customization script went here
// ...
// For the callback, we just need SOMETHING. ANYTHING. Don't complicate it.
await PostData(Toast, simpleCallback); // Of course, I added an await. Just in case. ;)
async function PostData(Toast, callback) {
await $.ajax({ // Again, awaiting just in case.
type: 'POST',
url: 'Ajax/' subdir,
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: JSON.stringify(dataObj),
success: function (result) {
if (showSuccess === true) {
Toast.fire({
title: 'Saved!',
icon: 'success',
timer: 2000
});
}
callback(); // I'm calling callback both here and in error handling
},
error: function (xhr, status, error) {
Toast.fire({
title: 'Error:',
text: 'Trouble saving data. Please contact the Web Team. (' error ')',
icon: 'error'
});
callback();
}
});
}
function simpleCallback() { // As I said: don't complicate it. This is as simple as it gets.
return false;
}
}
這不僅有效,而且讓我可以繼續并setTimeout從GoToNextPage()通話中洗掉 2 秒。使用console.log()標記,當我單擊“完成并保存”按鈕時,我能夠看到控制臺花時間瀏覽每個與 AJAX 相關的功能。一切都按順序運行,直到完成才讓頁面重定向。正是我的目標。
附加說明(2/28/2022):
To be thorough, I should also point out: obviously, you can (and should) remove awaits where not necessary, after testing what works best in your script. Be especially careful about adding awaits inside of for or each loops; sure, it might add only a tenth or two of a second to your load time, but if you don't need it there, why keep it?
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/434880.html
標籤:javascript jquery ajax asynchronous
