使 await return thenable,或者等待 awaitable 中的无限递归
Make await return thenable, or infinite recursion in awaiting awaitable
尝试想出 API,混合 promise 功能,例如:
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)
此代码创建递归。
重点是让smth
成为新创建的thenable实例。
将 then
与 null
打桩会使等待的结果不完整。
我想知道这是否可能,似乎有一些概念上的障碍,我无法理解。
承诺(或任何 thenable)自行实现是没有意义的。如果您已经拥有该对象,则无需等待。
, which would create infinite recursion in your case where it would resolve with itself, and you 。所以不要尝试这样做。兑现你的诺言,什么都不做 (undefined
)。
class Awaitable {
constructor () {
this.promise = Promise.resolve(undefined); // simplified
}
then(onfulfill, onreject) {
return this.promise.then(onfulfill, onreject);
}
// other methods
}
const smth = new Awaitable();
await smth; // works just fine now
console.log(smth);
正确的解决方案
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
脆弱的non-standard解决方案
通过解析调用堆栈可以检测 thenable
实例是否被 await
调用。这是基于 stacktrace-parser 包的解决方案:
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
必须为 FF/nodejs 增强启发式以巩固 - 这需要某种静态分析技巧。
尝试想出 API,混合 promise 功能,例如:
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)
此代码创建递归。
重点是让smth
成为新创建的thenable实例。
将 then
与 null
打桩会使等待的结果不完整。
我想知道这是否可能,似乎有一些概念上的障碍,我无法理解。
承诺(或任何 thenable)自行实现是没有意义的。如果您已经拥有该对象,则无需等待。
undefined
)。
class Awaitable {
constructor () {
this.promise = Promise.resolve(undefined); // simplified
}
then(onfulfill, onreject) {
return this.promise.then(onfulfill, onreject);
}
// other methods
}
const smth = new Awaitable();
await smth; // works just fine now
console.log(smth);
正确的解决方案
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
脆弱的non-standard解决方案
通过解析调用堆栈可以检测 thenable
实例是否被 await
调用。这是基于 stacktrace-parser 包的解决方案:
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
必须为 FF/nodejs 增强启发式以巩固 - 这需要某种静态分析技巧。