【问题标题】:Can I resolve a promise when a variable change without using deferr?我可以在不使用 deferr 的情况下在变量更改时解决承诺吗?
【发布时间】:2020-07-05 04:21:02
【问题描述】:

我正在将一些基于 Q-promise 的 typescript 代码转换为 ES6-promises。

在某个时刻,我使用了 Q.defer,在我的迁移中,我只是将 defer 重写为 ES6 承诺,就像在此评论中解释的那样: https://stackoverflow.com/a/49825137/13116953

如果可能的话,我试图摆脱这种延迟方法,并正在寻找替代解决方案。

我提出问题的原因是:

  1. 一般来说,延迟承诺被视为一种反模式
  2. 想知道这种情况是否是少数真正将延迟作为唯一方法的场景之一

这是我的场景:

// app start, this is my low level API
init() {
    commService.subscribe("myRecordId", {
        onRecordAdd: this.onAdd
    });
}

...

private _myRecord: MyRecordObj | null = null;
private _recordReceivedDef = newDeferred(); // was Q.defer()

// callback will be called when record is received
private readonly onAdd = (recordObj: MyRecordObj) => {
    this._myRecord = recordObj;
    this._recordReceivedDef.resolve(recordObj);
}

...

// here's my async code that requires the deferred
public readonly doStuff = async () => {
    // ...
    const myRec = await this._recordReceivedDef.promise;
    // use myRef
}

我的问题是:有什么办法可以摆脱这种延迟? 我正在考虑当_myRecord 更改时可以解决的问题,但不知道该怎么做。

旁注: 我在我们应用程序的其他部分使用 MobX,因此拥有

await when(() => this._myRecord); // of course _myRecord must be @observable

会很方便,但不幸的是我不能在这段特定的代码中使用 MobX。

非常感谢任何帮助。

非常感谢!

【问题讨论】:

    标签: javascript typescript promise es6-promise q


    【解决方案1】:

    对于可能感兴趣的人,还有另一种使用事件发射器方法的解决方案。 假设你有一个 EventEmitter 类实现了以下接口:

    // pseudo code
    type UnsubscribeFn = () => void;
    interface IEventEmitter<T> {
        /** Fires an event */
        emit(args: T): void;
        /** Subscribes to emissions of this event and provides an unsubscribe function */
        subscribe((args: T) => void): UnsubscribeFn;
    }
    

    您可以为您的客户提供如下whenAdded 函数

    // pseudo code
    class Subscriber {
        readonly onAddEmitter = new EventEmitter<MyRecordObj>();
    
        // app start
        init() {
            commService.subscribe("myRecordId", {
                onRecordAdd: this.onAdd
            });
        }
        
        onAdd = (rec: MyRecordObj) => {
               // do some stuff
               onAddEmitter.emit(rec);
        }
        
        whenAdded(): Promise<MyRecordObj> {
            return new Promise((res) => {
                const unsub = onAddEmitter.subscribe((record: MyRecordObj) => {
                    unsub();
                   res(record); 
                });
            });
        }
    }
    

    实现的目标是:

    • 摆脱 Q 承诺,转而使用 ES6 承诺
    • commService 事件 API 调整为基于 Promise 的事件 API

    【讨论】:

      【解决方案2】:

      假设initdoStuff 之前被调用,那么正确的方法是

      init() {
          this._myRecordPromise = new Promise((resolve, reject) => {
              commService.subscribe("myRecordId", {
                  onRecordAdd: (recordObj: MyRecordObj) => {
                      // callback will be called when record is received
                      resolve(this._myRecord = recordObj);
                  }
              });
          });
      }
      
      …
      
      private _myRecord: MyRecordObj | null = null;
      private _myRecordPromise: Promise<MyRecordObj>;
      
      …
      
      public readonly doStuff = async () => {
          …
          const myRec = await this._myRecordPromise;
          // use myRef
      }
      

      您甚至可以完全删除_myRecord,只保留_myRecordPromise

      但是,您可能需要考虑在收到记录之前根本不构建您的实例,请参阅Is it bad practice to have a constructor function return a Promise?

      如果在任意时间调用init,您将需要某种延迟模式,但您不需要newDeferred()。随便写

      init() {
          commService.subscribe("myRecordId", {
              onRecordAdd: this.onAdd
          });
      }
      
      …
      
      private _myRecordPromise: Promise<MyRecordObj> = new Promise(resolve => {
          this.onAdd = resolve;
      });
      private readonly onAdd: (recordObj: MyRecordObj) => void;
      

      【讨论】:

      • 谢谢,你帮助我从正确的角度看待 Promise
      猜你喜欢
      • 1970-01-01
      • 2013-11-03
      • 2018-10-15
      • 1970-01-01
      • 1970-01-01
      • 2017-03-27
      • 1970-01-01
      • 1970-01-01
      • 2020-12-20
      相关资源
      最近更新 更多