skip to Main Content

I have an array of functions such as:

let funcs = []
funcs.push(() => {window.x = fetch()})
funcs.push(() => {console.log(window.x)})
funcs.push(() => {console.log("Hello, world!")})

I would like the functions to be evoked one after the other, as in:

for (let func of funcs) {
  func();
}

However, I would like to concatenate the functions as if they were Promises so that the N+1 function is only ever invoked when the N function is resolved.

3

Answers


  1. Some of your functions involve asynchronous operations and you must make clear when you consider such a function "resolved". More precisely, if you want to wait for a certain result, your function must return a promise for that result. For example, fetch returns a promise for a response object:

    funcs.push(() => {return window.x = fetch(...)});
    

    but you could alternatively wait for the response body to be completely consumed:

    funcs.push(() => {return window.x = fetch(...).then(r => r.text())});
    

    Synchronous functions like your second and third need not return anything.

    With that you can use the following code to execute them one after another:

    let promise = Promise.resolve();
    for (const func of funcs) promise = promise.then(func);
    
    Login or Signup to reply.
  2. You can mix "normal" functions with functions returning promises in your funcs array, but you will have to make sure that the promise (if there is one …) is actually returned by the generating function and not only generated. I removed the curly braces ({,}) around your first function and also made sure that it returned a "sensible" value at the end (by supplying a further .then(r=>r.json()).then(d=>window.x=d.username) to it).

    Once the funcs array is set up you can run the indivudual function consecutively in an async function by using the await keyword like this:

    const url="https://jsonplaceholder.typicode.com/users/"; // public API for testing ...
    let funcs = [
     () => fetch(url+3).then(r=>r.json()).then(d=>window.x=d.username), // returns a promise
     () => {console.log(window.x+` is the same as global x: ${x}`)},    // returns nothing
     () => {console.log("Hello, world!")} ];                            // returns nothing
    async function doit(fns){ for (let fn of fns) await fn() }
    doit(funcs);

    It is generally not a good idea to work with a global variable like window.x. I only included it here in order to show that theoretically your approach can be made to work. However, a better way to get the result of a promise would be to return the desired value by the last chained then() method and pick it up by an expression that waits for it with await. But, of course, then your second function would also need to be changed in order not to be working with the global x but with a given argument val:

    const url="https://jsonplaceholder.typicode.com/users/"; // public API for testing ...
    let funcs = [
     () => fetch(url+3).then(r=>r.json()).then(d=>d.username), // returns a promise
     (val) => {console.log(`This is val: ${val}`)},            // returns nothing
     () => {console.log("Hello, world!")} ];                   // returns nothing
    async function doit(fns){ 
     let v;
     for (let fn of fns) v=await fn(v); // v gets re-evaluated each time!
    }
    doit(funcs);
    Login or Signup to reply.
  3. According to mdn web docs, fetch() will return Promise, so it will print Hello, world! first instead of value of window.x because window.x is Promise. So, you must resolve the fetch response first before printing it with the async function like this:

    let funcs = []
    funcs.push(() => {
      window.x = new Promise((resolve, reject) => {
        fetch('https://dummyjson.com/carts/1')
        .then(result => resolve(result.json()))
        .catch(error => reject(error));
      });
    });
    funcs.push(async() => { console.log(await window.x) });
    funcs.push(() => { console.log("Hello, world!") });
    
    (async() => {
      for (let func of funcs) {
        await func();
      }
    })()
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search