I have a class method that chains together other methods in the class, and also calls a method on another instance of the class:
class Thing {
doSomething(nextThing) {
return new Promise((resolve) =>
this.initialize()
.then(() => this.doA())
.then(() => {
nextThing.initialize(); // call initialize() on another instance
return this.doB();
})
.then(() => this.doC())
.then(resolve)
);
}
initialize() {
return new Promise((resolve) => {
// take a long time to do something
// ...
// ...
resolve();
});
}
doA() { return new Promise((resolve) => resolve()); }
doB() { return new Promise((resolve) => resolve()); }
doC() { return new Promise((resolve) => resolve()); }
}
const thing1 = new Thing();
const thing2 = new Thing();
thing1.doSomething(thing2);
Calling the function on the other class instance locks up the flow of the chain, however; this.doB()
and nextThing.initialize()
will run simultaneously (as desired), but this.doC()
won't run until nextThing.initialize()
has resolved.
What's the right way to make sure this flows as expected, with nextThing.initialize()
and this.doB()
starting simultaneously, and starting this.doC()
immediately after this.doB()
resolves? It's okay if nextThing.initialize()
resolves after this.doC()
.
When you do this structure:
return new Promise(resolve => {
// run some long synchronous piece of code
resolve(...);
});
Here's what happens.
resolve(...)
to resolve the previously created promise.then()
handlers are called on the previous promise.So, a promise calls the executor callback synchronously. It doesn't allow you to "run anything in the background". Javascript is still single threaded.
You can't use a promise to make synchronous code into asynchronous code. You can use some promise techniques to change the scheduling of when code runs, but synchronous code in Javascript is still synchronous and blocking code in Javascript no matter when it runs.
Promises are purely a notification system for notifying you when some other operation has told a promise that it is now resolved or rejected. They don't magically convert synchronous code into asynchronous code.
So, bottom line, you can't use promises to take a synchronous, long-running initialize()
function and somehow make it non-blocking or asynchronous.
What's the right way to make sure this flows as expected, with nextThing.initialize() and this.doB() starting simultaneously,
If nextThing.initialize()
is synchronous and blocking, it can't run simultaneous with anything. node.js runs your Javascript single threaded. One piece of Javascript running at a time. Promises can't change that.
and starting this.doC() immediately after this.doB() resolves
Since this.doB()
and this.doC()
both return promises, then you chain the promises with chained .then()
handlers to sequence those operations. Your code appears to already do that.
For info about options for off-loading long running synchronous code outside the current node.js single Javascript thread, see this other answer:
Make time intensive function asynchronous
FYI, perhaps this is just pseudo code, but there's never a reason to so this:
return new Promise((resolve) => resolve());
You can instead just do:
return Promise.resolve();.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With