skip to Main Content

I’m trying to create a routine to sequentially execute a series of test processes. I can’t even figure out how to create a simulation function for a long process. It uses a timer to ensure sequential order (one process doesn’t start until the previous one finishes). I’ve tried many things, here is an example of what seems like it might work…

async function someLongProcess(myInfoStr) {
    // Some async process that takes time
    console.log(myInfoStr + ": Process Starting");
    setTimeout(()=>{
        console.log(myInfoStr + ": Process Finishing");
        return myInfoStr + ": Process Finished";
    }, 1000);
}

someLongProcess("Test A").then(
    function(value) { console.log(value) },
    function(error) { console.log("Oh oh!: " + error) }
);

The result I wanted: "Test A: Process Starting", "Test A: Process Finishing", "Test A: Process Finished".

The result I got: "Test A: Process Starting", "undefined", "Test A: Process Finishing".

I understand it didn’t work because the return was inside the anonymous function, and someLongProcess didn’t return any promise at all. And of course I already tried to just put the return after the setTimer block which also failed: "Test A: Process Starting", "Test A: Process Finished", "Test A: Process Finishing". I’ve been dorking around with this for hours. Is there a way to do it? TIA

2

Answers


  1. You have to return Promise by using new Promises().

    That takes two arguments of first for fulfilled and another for rejection obviously we get in our catch block.

    And you can’t get error in then block, it will visible only in catch block. Below I have added isError argument to simulate that and seconds argument for setTimeout

    More about Promise

    async function someLongProcess(myInfoStr,seconds,isError) {
        // Some async process that takes time
        return new Promise((resolve,reject)=>{
            if(isError){
            return reject("I am an errorrr from "+myInfoStr);
          }
          setTimeout(()=>{
            console.log(myInfoStr + ": Process Finishing");
            resolve(myInfoStr + ": Process Finished")
          }, seconds);
        });
    }
    
    const test_1 = "Test A";
    console.log(test_1 + ": Process Starting");
    someLongProcess(test_1,1000).then(value=>{
      console.log(value);
      return value;
    }).catch(error=>{
      console.error(error);
      return error
    });
    .as-console-wrapper { max-height: 100% !important; }
    Login or Signup to reply.
  2. MDN’s description for async reads:

    An async function declaration creates an AsyncFunction object. Each time when an async function is called, it returns a new Promise … .

    This means, your someLongProcess() async function does return a promise.

    But your problem is (as you have correctly identified): The return statement returns from the closest function; in this case, your anonymous callback function for setTimeout().

    Callback-based functions like setTimeout() can be "promisified" by using the Promise constructor, to have access to the resolve (and reject) function of its executor function.

    To "promisify", simply call the callback-based function in the executor, and resolve it in the callback-based function’s callback:

    function timeout(ms) {
      return new Promise(resolve => {
        setTimeout(() => resolve(), ms);
      });
    }
    
    // Example
    console.log("Start");
    timeout(2000).then(() => {
      console.log("Finished");
    });

    Note: The async keyword allows for promises to be awaited; the Promise constructor provides the resolve and reject functions. You can declare a function as async while also using the Promise constructor for both benefits; however, in the above example async is not necessary.

    Using the above timeout() async function (async since it returns a promise) allows for a simpler someLongProcess() function.

    Example with chained promises:

    function timeout(ms) {
      return new Promise(resolve => {
        setTimeout(() => resolve(), ms);
      });
    }
    
    // Returns a promise
    function someLongProcess(myInfoStr) {
      console.log(myInfoStr + ": Process Starting");
      return timeout(1000).then(() => {
        console.log(myInfoStr + ": Process Finishing");
        return myInfoStr + ": Process Finished";
      });
    }
    
    someLongProcess("Test A").then(
      function(value) { console.log(value) },
      function(error) { console.log("Oh oh!: " + error) }
    );

    Example with async:

    function timeout(ms) {
      return new Promise(resolve => {
        setTimeout(() => resolve(), ms);
      });
    }
    
    async function someLongProcess(myInfoStr) {
      console.log(myInfoStr + ": Process Starting");
      await timeout(1000);
      console.log(myInfoStr + ": Process Finishing");
      return myInfoStr + ": Process Finished";
    }
    
    someLongProcess("Test A").then(
      function(value) { console.log(value) },
      function(error) { console.log("Oh oh!: " + error) }
    );

    I was unaware that the .then() method accepts a second parameter for a onRejected callback. I usually see .catch() in favour of it, but I guess I learned something from your question as well!

    Make sure to learn about the benefits of both async/await and the Promise constructor. Since either approaches return promises, both allow for chained promises.

    For the future: You should also be aware of Promise.all() and similar functions, should you want to run multiple async functions in parallel instead of sequentially.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search