Can you share more of the code that uses the await keyword? You mention that this calls other “programs”, but I am not sure if you are referencing another App, a Workflow, another Code Block, etc…
When does localStorage update? What causes the update? What triggers this code block? There are many pieces that I do not have insight into to which might be causing the data to be retrieved early/late/never. A thing that may be helpful to do is setup a very basic version of your logic to build up to your final code solution.
await awaitTfrDocToStorage.trigger(); // this builds a new doctor2 file with selections blank. it also sets all rows of Continue2 to YES
// await awaitprocesses.trigger();
await console.log("Finished awaitTfrDocToStorage.");
// await RestoreDoctors2.trigger(); // this puts the Doctors2 table into table2.
await console.log("waiting for 700 ms is Finished now we will bring mCONTINUE from localStorage at beginning");
await new Promise(resolve => setTimeout(resolve,700));
let mCONTINUE = localStorage.values.mContinue;
await new Promise(resolve => setTimeout(resolve,700));
await console.log(`MCONTINUE equals ${mCONTINUE}`);
async function runLoop() {
await new Promise(resolve => setTimeout(resolve,700));
await localStorage.setValue('mContinue', mCONTINUE);
await console.log(`This is recovery from LocalStorage at top of function, mCONTINUE = ${mCONTINUE}`);
await new Promise(resolve => setTimeout(resolve,700));
await RestoreDoctors2.trigger();
await console.log("Beginning of loop. waiting 700 ms, This is after RestoreDoctors2 to get the value of mCONTINUE from table2");
await new Promise(resolve => setTimeout(resolve,700));
mCONTINUE = localStorage.values.mContinue ;
await new Promise(resolve => setTimeout(resolve,700));
await console.log(`This is retrieval from localStorage at beginning of loop, and before if statement mCONTINUE equals ${mCONTINUE}`);
await new Promise(resolve => setTimeout(resolve,700));
if (mCONTINUE === "YES" ) {
// await RestoreDoctors2.trigger();
await console.log("waiting 700 ms for RestoreDoctors2 before loop");
await new Promise(resolve => setTimeout(resolve,700));
let mCONTINUE = localStorage.values.mContinue ;
await console.log(`mCONTINUE from localStorage equals ${mCONTINUE}`);
await new Promise(resolve => setTimeout(resolve,700));
await awaitTfrDocToStorage2.trigger();
await new Promise(resolve => setTimeout(resolve,700));
mCONTINUE = localStorage.values.mContinue ;
await console.log(`This is recovery from LocalStorage after awaitTfrDocToStorage2, mCONTINUE = ${mCONTINUE}`);
// await RestoreDoctors2.trigger();
await console.log("waiting 700 ms for RestoreDoctors2 before loop");
await new Promise(resolve => setTimeout(resolve,700));
mCONTINUE = localStorage.values.mContinue ;
await console.log(`Fibished reading Table2 after awaitTfrDocToStorafe2 , mCONTINUE = ${mCONTINUE}`);
await console.log(`About to wait for 700 ms before continuing after awaitTFRDocToStorage2`);
await new Promise(resolve => setTimeout(resolve,700));
await awaitprocesses2.trigger();
await new Promise(resolve => setTimeout(resolve,700));
mCONTINUE = localStorage.values.mContinue;
await console.log(`This is recovery from LocalStorage after awaitprocesses2, mCONTINUE = ${mCONTINUE}`);
// await RestoreDoctors2.trigger();
await console.log(`About to wait for 600 ms after RestoreDoctors2`);
// mCONTINUE = localStorage.values.mContinue;
let mcount = table2.data.filter(row => row.extra1 === "ZZ").length;
await console.log(`Doctors remaining after 700ms wait equals ${mcount}`);
mCONTINUE = localStorage.values.mContinue ;
await console.log(`About to wait for 700 ms after counting doctors not processed`);
await new Promise(resolve => setTimeout(resolve,700));
await new Promise(resolve => setTimeout(resolve,700));
await console.log(`Waited 700 ms from local storage at bottom of if in loop - mCONTINUE equals ${mCONTINUE}`);
await console.log(`About to wait for 600 ms before end of loop, mCONTINUE equals ${mCONTINUE}`);
await new Promise(resolve => setTimeout(resolve,600));
// Call the function again
return runLoop();
}
else
{
// await RestoreDoctors2.trigger(); // this puts the Doctors2 table into table2.
// const mCONTINUE = table2.data[0].Continue2;
mCONTINUE = localStorage.values.mContinue;
await console.log(`About to Stop- mCONTINUE from localStorage equals ${mCONTINUE}`);
await console.log("Loop stopped!");
}
}
runLoop();
await console.log("Process complete.");
Off the bat, I can see that there is some extra process control via timeouts. I do not recommend this. You also are heavily using the await in some place where I don’t believe it is necessary, such as the console.log() areas.
Do you have the output of those logs available as well? I’d be interested to see the sequence of events captured this way.
The overall logic seems to be in an async function, and you only ever call this for recursion, with no parameters, so it makes me wonder if it is necessary at all… maybe a while loop works better? In addition, you don’t seem to be awaiting the response of the function so it might be returning in the loop before the long series of awaits and timeouts completely processes.
Digging a little deeper, I would probably suggest that you use success event handlers in each of your queries to run each loop or offload the logic to a workflow where you can take advantage of the built in Loop block components.
Maybe some other users have better suggestions for your specific code, but I’m thinking about some general tips that might help with your debugging that I have found useful.
Here is the code I have come up with after spending a few hours with ChatGPT.
await awaitTfrDocToStorage.trigger();
let mCONTINUE = "YES";
localStorage.setValue('mContinue', mCONTINUE);
async function runLoop() {
do {
if (mCONTINUE === "YES") {
await awaitTfrDocToStorage2.trigger();
await awaitprocesses2.trigger();
await RestoreDoctors4.trigger();
const mcount = RestoreDoctors4.data.remaining;
console.log(`Doctors remaining = ${mcount}`);
if (mcount === 0) {
mCONTINUE = "NO";
localStorage.setValue('mContinue', "NO");
}
}
} while (mCONTINUE === "YES");
console.log("Exited loop");
}
await runLoop();
console.log("Process complete.");
This code works but it cannot end. This because changes to "mContinue" are written to localStorage are not recognized by active code. In reality, the code makes a snapshot of your local Storage at the outset and that is all it sees even though localStorage is being updated by the code itself.
So ChatGPT tried to end the loop by watching the doctor filter drop to 0. But again the mCount does not get updated. It just stays at 10 even though I can watch table2 reducing the doctor filter to 0.
I have another thought on this that I will try tomorrow.
I thought I would let you know what I found from ChatGPT for your information.
Your mcount variable is declared as a const. You should use let or var to declare that value, I believe as you cannot update or reassign const variables like you are trying.
You are also declaring this within your loop.
Since your first iteration will always require the initial query data, you should move some of that outside of the loop block:
await awaitTfrDocToStorage.trigger();
await RestoreDoctors4.trigger();
// this isn't necessary here, since the do-while will always trigger once, but if you are using it to declare something outside of the loop it will need to run.
let mCONTINUE = "YES";
let mcount = RestoreDoctors4.data.remaining;
// same here. this can stay within the loop since you force it to run the first time by declaring mCONTINUE as "YES"
localStorage.setValue('mContinue', mCONTINUE);
async function runLoop() {
do {
if (mCONTINUE === "YES") {
await awaitTfrDocToStorage2.trigger();
await awaitprocesses2.trigger();
await RestoreDoctors4.trigger();
mcount = RestoreDoctors4.data.remaining;
console.log(`Doctors remaining = ${mcount}`);
if (mcount === 0) {
mCONTINUE = "NO";
localStorage.setValue('mContinue', "NO");
}
}
} while (mCONTINUE === "YES");
console.log("Exited loop");
}
await runLoop();
console.log("Process complete.");
You could follow the same pattern you used for tracking mContinue/mCONTINUE to track mcount.
I have worked with workstation based software (like Visual FoxPro) for the early part of my career and these languages did not have all the storage problems of web based langages.
I also find the syntax of Java Script very difficult.
It seems that a lot of people are migrating to Python. I am just guessing that it is a little more user friendly. But I don't know.
I would not wish Java Script on my worst enemy. Its debugger is pretty much useless, the storage is difficult and the syntax is terrible. I am sure there must be better web based languages out there.
I find MySql much better. I think I should have developed this with MySql using Stored P:rocedures.
Anyway, I will poke around this a bit more. I think there is a way around this.
Mike, you are certainly not alone in the sentiments around JavaScript! It is the target of much ire and humor among developers, but usually those faults are grounded in at least something of a concept. Not to get too deep, but it is a driver of so much of web design that it is largely unavoidable in practice. Python is a good alternative, and any SQL based work you can manage BEFORE rendering will most certainly improve your own development experience.
For me (in general), I just try to learn what I need when I need it. I have a pretty good sense for how a language should operate and how to figure out the underlying patterns from there. One of the nice things about Retool is that you get to explore a lot of different approaches and hopefully one of them is in your sweet spot. A lot of work being done at my company involves a mix of well formed SQL, Stored Procedures, API calls, and then the code to transform/compile/process as needed.
This is why I mentioned perhaps looking into offloading some of your process from your App to a Workflow which you trigger from the App. Workflows give me a more robust sense of the staging of my data sources and better control over how I want to log/report/use it.
I have workflow working quite well. I can design web forms now with all the elements of First Name, Last Name etc. I can set up fonts and colours. I can add graphics. And I can get the forms emailed manually or on an automatic schedule. I am very happy with it now that I have figured it out.
One thing I am also learning is the immense power of AGI as support. I use Chat GPT, Microsoft Co Pilot and Google Gemini and am very, very impressed with the helpful answers and the 2 way dialogue for drilling down.
I mentioned the poor debugging of Java Script. Somehow AGI has figured this out and is not only able to tell you which parts of your code are wrong, it can also rewrite it for you. This is beyond wonderful.
Anyway, I am going to work on my own code problem tonight and I will report my results back to the Community.
The idea is that I count the rows in table2 before the loop starts. That value is CCNT. I do not put it in local Storage. I just let it become a unchangeable variable with "const".
I then establish a counter as CCNT2 using "let".
Each time I go through the loop, CCNT2 is incremented by 1.
The loop stops when CCNT2 is greater than CCNT.
Its just a matter of understanding how the memory works. The solution is quite simple.
Mike
await awaitTfrDocToStorage.trigger();
let mCONTINUE = "YES";
let CCNT2 = 0;
const CCNT = table2.data.filter(row => row.Lname.trim().toLowerCase() > "a" ).length;
console.log(`CCNT = ${CCNT}`);
async function runLoop() {
do {
if (mCONTINUE === "YES") {
await awaitTfrDocToStorage2.trigger();
await awaitprocesses2.trigger();
await RestoreDoctors4.trigger();
CCNT2 = CCNT2 + 1;
console.log(`CCNT2 = ${CCNT2}`);
if (CCNT2 > CCNT) {
mCONTINUE = "NO";
}
}
} while (mCONTINUE === "YES");
console.log("Exited loop");
}
await runLoop();
console.log("Process complete.");