简体   繁体   English

为什么我的链式承诺会被阻止?

[英]Why is my chained promise blocking?

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. this.doB()nextThing.initialize()将同时运行(根据需要),但this.doC()将不会运行,直到nextThing.initialize()已解决。

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? 什么是确保按预期流动的正确方法, nextThing.initialize()this.doB()同时启动,并在this.doB()结束后立即启动this.doC() It's okay if nextThing.initialize() resolves after this.doC() . 如果nextThing.initialize()this.doC()之后解析,那也this.doC()

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 创建一个新的promise对象
  2. The promise executor callback is called synchronously as part of the promise constructor execution promise执行器回调作为promise构造函数执行的一部分被同步调用
  3. Your long-running synchronous code is called om that executor callback 您长时间运行的同步代码称为om执行程序回调
  4. You call resolve(...) to resolve the previously created promise 您调用resolve(...)来解析先前创建的promise
  5. You return from the promise executor 您从promise执行者返回
  6. The promise constructor returns promise构造函数返回
  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. 稍后(在当前的Javascript将控制权返回给系统之后),在先前的承诺上调用.then()处理程序。

So, a promise calls the executor callback synchronously. 因此,promise会同步调用执行程序回调。 It doesn't allow you to "run anything in the background". 它不允许你“在后台运行任何东西”。 Javascript is still single threaded. Javascript仍然是单线程的。

You can't use a promise to make synchronous code into asynchronous code. 您不能使用promise将同步代码转换为异步代码。 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. 您可以使用一些承诺技术来更改代码运行时的调度,但Javascript中的同步代码仍然是同步的,并且无论何时运行,都会阻止Javascript中的代码。

Promises are purely a notification system for notifying you when some other operation has told a promise that it is now resolved or rejected. Promise纯粹是一个通知系统,用于在其他操作已经告知承诺现在已经解决或拒绝时通知您。 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. 所以,最重要的是,你不能使用promises来获取一个同步的,长时间运行的initialize()函数,并以某种方式使它成为非阻塞或异步。

What's the right way to make sure this flows as expected, with nextThing.initialize() and this.doB() starting simultaneously, 什么是确保它按预期流动的正确方法,同时启动nextThing.initialize()和this.doB(),

If nextThing.initialize() is synchronous and blocking, it can't run simultaneous with anything. 如果nextThing.initialize()是同步和阻塞的,则它无法与任何内容同时运行。 node.js runs your Javascript single threaded. node.js运行您的Javascript单线程。 One piece of Javascript running at a time. 一次运行一个Javascript。 Promises can't change that. 承诺不能改变这一点。

and starting this.doC() immediately after this.doB() resolves 并在this.doB()结束后立即启动this.doC()

Since this.doB() and this.doC() both return promises, then you chain the promises with chained .then() handlers to sequence those operations. 由于this.doB()this.doC()都返回promise,然后使用链式.then()处理程序链接promises以对这些操作进行排序。 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: 有关在当前node.js单个Javascript线程之外卸载长时间运行的同步代码的选项的信息,请参阅此其他答案:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM