I am converting some Q-promise based typescript code to ES6-promises.
At a certain point, I used Q.defer and in my migration I just rewritten defer as an ES6 promise like explained in this comment: https://stackoverflow.com/a/49825137/13116953
I was trying to get rid of this defer approach, if possible, and was looking for alternative solutions.
Reasons of my question are:
Here's my scenario:
// 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
}
My question is: is there a way I can get rid of this defer?
I was thinking of something that resolves when _myRecord
changes, but have no idea how to do it.
Side note: I use MobX in other parts of our app, thus having
await when(() => this._myRecord); // of course _myRecord must be @observable
would be handy, but unfortunately I cannot use MobX in this particular piece of code.
Any help is much appreciated.
Thanks a lot!
Assuming init
is called before doStuff
, the proper way would be
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
}
You might even drop the _myRecord
completely and keep only the _myRecordPromise
.
However, you might want to consider not constructing your instance at all before the record is received, see Is it bad practice to have a constructor function return a Promise?.
If init
is called at some arbitrary time, you will need some kind of defer pattern, but you don't need newDeferred()
for that. Just write
init() {
commService.subscribe("myRecordId", {
onRecordAdd: this.onAdd
});
}
…
private _myRecordPromise: Promise<MyRecordObj> = new Promise(resolve => {
this.onAdd = resolve;
});
private readonly onAdd: (recordObj: MyRecordObj) => void;