Home > Blockchain >  Better way to wait for a function until next step javascript
Better way to wait for a function until next step javascript

Time:11-22

I am writing a browser-based javascript to scrape the input value by user and provide feedback. And in the page, you have to click on different areas for the desired element to show. I am trying to see if there is a way I can get javascript to wait until the element returns before I start going to the next one. Right now I just use setTimeout, but I have to loop all the elements I want to get, so nasty nested functions. trying to see if there is a more elegant solution. I used to write VBA, so I am not so familiar with async web API. still learning

function a(){
document.getElementById('1').click()
setTimeout(function(){document.getElementById('1a');addmessage;b;}),5000}
}
function b(){
document.getElementById('2').click()
setTimeout(function(){document.getElementById('2a');addmessage;c;}),5000}
}
function c(){
document.getElementById('3').click()
setTimeout(function(){document.getElementById('3a');addmessage;d;}),5000}
}
function addmessage(){
//this is the function I used to add element do some operation and add to dialog box
}

etc..

what I imagined is like below

function addmessage(element_to_click,element_to_collect){
// click element_to_click
// wait 5s
// collect innertext from element_to_collect
// do some operation, generate a message
//add message to dialog box
}

so I can do something like

addmessage(1,1a)
addmessage(2,2a) <--- this won't execute until the first is complete.

CodePudding user response:

If I'm understanding the question correctly, you can start with a promise wrapper around setTimeout:

const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));

Then addMessage could be:

async function addMessage(element_to_click, element_to_collect) {
    element_to_click.click();
    await delay(5000);
    return element_to_collect.textContent;
}

You didn't say what you wanted to do with the text, so I've just had it return it.

Then you can either write a loop or a series of calls:

async function run() {
    const a = await addMessage(
        document.getElementById("1"),
        document.getElementById("???"),
    );
    const b = await addMessage(
        document.getElementById("2"),
        document.getElementById("???"),
    );
    const c = await addMessage(
        document.getElementById("2"),
        document.getElementById("???"),
    );

    // ...do something with `a`, `b`, and `c`...
}

When calling run, don't forget to handle promise rejection (in case something goes wrong).


You've said that after the click, "...the page needs a few seconds to load..." Hardcoded timeouts are fragile and often break. Instead of a timeout, try to hook into something that will change, perhaps via a MutationObserver on the element you're "collecting" from.

CodePudding user response:

You can make your code wait for a timeout to complete by wrapping it in a Promise and using the async await pattern:

// Return a new Promise immediately, that completes at the end of the timeout
function addmessage(element_to_click, element_to_collect) {
  return new Promise((resolve, reject) => {
    // do whatever

    // resolve the Promise after 5s
    setTimeout(resolve, 5000) 
    // you can also resolve the Promise on any other event, like user input
    // (or use `reject` when an error occurs)
    // you can pass a return value to `resolve` like resolve(input.value)
  })
}

// `async` functions also return a Promise immediately
async function addMessages() {
  // `await` will block until Promise completes and
  // returns the resolved value to be used synchronously within the async func
  const in1 = await addmessage('1', '1a') 
  const in2 = await addmessage('2', '2a')
  const in3 = await addmessage('3', '3a')
}

addMessages()
  • Related