Why is my chained promise blocking?

烈酒焚心 提交于 2021-02-04 14:01:30

问题


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().


回答1:


When you do this structure:

return new Promise(resolve => {
    // run some long synchronous piece of code
    resolve(...);
});

Here's what happens.

  1. A new promise object is created
  2. The promise executor callback is called synchronously as part of the promise constructor execution
  3. Your long-running synchronous code is called om that executor callback
  4. You call resolve(...) to resolve the previously created promise
  5. You return from the promise executor
  6. The promise constructor returns
  7. You return from the host function and the line of code after this function call will get to run
  8. Sometime later (after the current piece of Javascript returns control back to the system), the .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();.


来源:https://stackoverflow.com/questions/50825071/why-is-my-chained-promise-blocking

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!