Updated: I've tried to provide a better context for this discussion with my new post: "Thenable: how to make a JavaScript object await-friendly, and why it is useful".
Asking for opinions. Would it make sense to have a standard symbol for the object's default awaitable, e.g. Symbol.promise
, by analog to Symbol.asyncIterator
?
I sometimes use the following pattern, in a nutshell (codepen):
class AsyncOperation {
#promise = null;
constructor(ms) {
this.#promise = new Promise(r => setTimeout(r, ms));
}
then(resolve, reject) {
return this.#promise.then(resolve, reject); }
}
async function main() {
await new AsyncOperation(1000);
console.log("completed!")
}
This works, because we've made an instance AsyncOperation
to be thenable
.
If however we had Symbol.promise
, it'd be less boilerplate code for AsyncOperation
:
class AsyncOperation {
#promise = null;
constructor(ms) {
this.#promise = new Promise(r => setTimeout(r, ms));
}
get [Symbol.promise]() { return this.#promise; }
}
Wouldn't Symbol.promise
be useful?
Here is a less contrived snippet, adapted from some real-life code of mine:
const subscription = createSubscription(
cancellationToken, eventSource, "eventName");
try {
await subscription;
}
finally {
subscription.close();
}
The relevant part of createSubscription
code:
// ...
return Object.freeze({
close: () => unsubscribe(),
then: (resolve, reject) => promise.then(resolve, reject)
});
I'd like to be able to do:
// ...
return Object.freeze({
close: () => unsubscribe(),
get [Symbol.promise]() { return promise; }
});
Of course, I could as well just expose promise
as a property getter (and do await subscription.promise
), or as a method, similar to RxJS' toPromise()
.
Yet the same arguments could possibly be used for iterable objects, which nevertheless expose their iterators via [Symbol.iterator
] or [Symbol.asyncIterator
]. Not via something like array.iterator
or array.getIterator()
.
IMO, it'd be convenient if await
looked for [Symbol.promise]
in the same way the for...of
and for await...of
loops look for iterators.
Given that we already can await
any expression in JavaScript (not just a Promise
or "thenable"), I think that would make sense.
Probably, the common JavaScript way of calling an async operation is less OOP-ish:
I might image that you want an object to get a
cancel
method or aprogress
property, which isn't standard by itself. There's a Stage 1 proposal for Cancellation API, but who knows how it will look like.Looking into Subscription code, if a promise is one-time only, why doesn't it close itself on finish? Then it will be just