0

I have a file, myClass.js which has a class with function in it.

class MyClass {
    func1(param1, param2) {
        return new Promise((resolve, reject) => {
            resolve(param1+param2);
        })
    }
} 

const myObj = new MyClass();

module.exports = myObj;

Then I call that function from another file and feed it through Promise.all.

const myObj = require('myClass.js') 
let funcPromise1 = myObj.func1(1, 2);
let funcPromise2 = myObj.func1(2, 3);
let funcPromise3 = myObj.func1(3, 4);

Promise.all([funcPromise1, funcPromise2, funcPromise3])
    .then(values=> {
        console.log(values)
    });

The problem is that the func1 gets invoked when I assign it to the variable. I could wrap it in another Promise, but that seems like an anti-pattern.

let funcPromise1 = new Promise((resolve, reject) => { myObj.func1(1, 2).then(sum=>{resolve(sum)}).catch(err=>{reject(err)});

I could just place the function in the promise all, but it starts to get hard to follow.

How can I not invoke this function immediately?

Matt Kuhns
  • 1,328
  • 1
  • 13
  • 26
  • 1
    Why don't you want you functions to be invoked? You need to promises they return. When *should* they be invoked if not before passing them to `Promise.all()`? – Mark Apr 26 '19 at 16:54
  • I want them to be invoked in the promise.all, so if one of them fail, I can catch it then. The actual code it transactional, so I would rollback on failure. – Matt Kuhns Apr 26 '19 at 16:57
  • Calling the fns within Promise.all() or assigning to variables then passing to Promise.all have the same effect. – enapupe Apr 26 '19 at 17:22
  • @MattKuhns It doesn't matter when the function is called, as long as it returns a promise then `Promise.all` will catch any failures. – Bergi Apr 26 '19 at 17:59
  • Btw, you should not use `class` syntax when you want to export a singleton instance. Just use an ordinary object literal. – Bergi Apr 26 '19 at 17:59

1 Answers1

0

Promises are executed immediately

However, you can simply wrap the promises in another function that you can explicitly invoke only when you want them to execute. In the following example, your myObj.func1 gets called early, but the actual promises are delayed until after a button is clicked.

class MyClass {
  func1(param1, param2) {
    return () => new Promise((resolve, reject) => {
      console.log('executed', param1, param2);
      resolve(param1 + param2);
    })
  }
}

const myObj = new MyClass();
let funcPromise1 = myObj.func1(1, 2);
let funcPromise2 = myObj.func1(2, 3);
let funcPromise3 = myObj.func1(3, 4);

document.getElementById("btn").addEventListener('click', () => {
  Promise.all([funcPromise1(), funcPromise2(), funcPromise3()])
    .then(values => {
      console.log(values)
    });
});
<button id="btn">Go</button>

A more complex approach is to wrap each func1 promise with another promise that will invoke func1 only when some other promise is resolved. This is effectively the same as the first solution (both are just a way to delay the call to new Promise inside func1), but it could be preferred in your situation because func1 doesn't change and the call to Promise.all doesn't change, only the initialization of the funcPromiseN variables.

class MyClass {
  func1(param1, param2) {
    return new Promise((resolve, reject) => {
      console.log('executed', param1, param2);
      resolve(param1 + param2);
    })
  }
}

const clicked = new Promise(res => {
  document.getElementById("btn").addEventListener('click', () => res());
});
const delayed = (p, fn, ...args) => p.then(() => fn(...args));

const myObj = new MyClass();
let funcPromise1 = delayed(clicked, myObj.func1, 1, 2);
let funcPromise2 = delayed(clicked, myObj.func1, 2, 3);
let funcPromise3 = delayed(clicked, myObj.func1, 3, 4);


clicked
  .then(() => Promise.all([funcPromise1, funcPromise2, funcPromise3]))
  .then(values => {
    console.log(values)
  });
<button id="btn">Go</button>
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331