Trying to come up with API, mixing in promise functionality like:
class Awaitable {
constructor () {
this.promise = Promise.resolve()
}
then (fn) {
// awaited result must be _this_ instance
return this.promise.then(() => fn(this))
}
}
let smth = await (new Awaitable())
console.log(smth)
This code creates recursion.
The main point is to have smth
to be the newly created thenable instance.
Stubbing then
with null
makes awaited result incomplete.
I wonder if that's possible at all, seems like there's some conceptual hurdle, I can't wrap my head around.
Symbol.thenable proposal.
import { parse as parseStack } from 'stacktrace-parser'
class Awaitable {
constructor () {
this.promise = Promise.resolve()
},
[Symbol.thenable]: false,
then(fn) {
this.promise.then(() => fn(this))
return this
}
}
let smth = await (new Awaitable())
console.log(smth.then) // function
Detecting if thenable
instance is called by await
is possible by parsing callstack. Here's solution based on stacktrace-parser package:
import { parse as parseStack } from 'stacktrace-parser'
class Awaitable {
constructor () {
this.promise = Promise.resolve()
}
}
Object.defineProperty(Awaitable.prototype, 'then', {
get() {
let stack = parseStack((new Error).stack)
// naive criteria: if stacktrace is leq 3, that's async recursion, bail out
// works in webkit, FF/nodejs needs better heuristic
if (stack.length <= 3) return null
return (fn) => {
this.promise.then(() => {
fn(this)
})
return this
}
}
})
let smth = await (new Awaitable())
console.log(smth.then) // function
The heuristic must be enhanced for FF/nodejs, to solidify - that'd require sort of static analysis wizardy.