从你想要的:
await this.loadingWrap(this.someAsyncFunction({ param: 'Value'}))
这不起作用,因为它将参数视为嵌套函数。操作顺序将是:
- 称呼
this.someAsyncFunction({ param: 'Value'})
- call
this.loadingWrap(x)wherex是第1步的返回值
这种类型的函数求值与数学函数完全一样,在哪里求值f(g(x))( f of g , given x),首先在给定 value 的情况下对g求值x,然后使用结果对f求值。
一个可能的解决方案...
您也许可以使用 JavaScript 的Proxy对象。正如文档所说,您可以通过使用apply陷阱在函数上使用它们。
您将编写处理程序以处理任何尝试使用加载标志的函数。
const handler = {
apply: async function(target, thisArg, argumentsList) {
thisArg.loading = true
await target.apply(thisArg, argumentsList)
thisArg.loading = false
}
}
然后,您将someAsyncFunction通过像这样创建代理来创建您的成员函数:
YourClass.prototype.someAsyncFunction = new Proxy(someAsyncFunction, handler);
然后你这样称呼它:
// inside some other async member function...
await this.someAsyncFunction({ param: 'Value'})
这是一个可运行的示例(页面上没有任何内容,只有控制台输出):
class MyObj {
constructor() {
this.loading = false
}
async someAsyncFunction(val) {
console.log(`entering someAsyncFunction: loading = ${this.loading}`)
console.log(`calling this.asyncLoad...`)
await this.asyncLoad({
value: val
})
console.log(`exiting someAsyncFunction: loading = ${this.loading}`)
}
}
async function asyncLoad(params) {
return new Promise(resolve => {
console.log(`entering asyncLoad: loading = ${this.loading}, value = ${params.value}`)
setTimeout(() => {
console.log(`exiting asyncLoad: loading = ${this.loading}, value = ${params.value}`)
resolve()
}, 1000)
})
}
const handler = {
apply: async function(target, thisArg, argumentsList) {
console.log('PROXY: setting load to true...')
thisArg.loading = true
console.log('PROXY: calling the proxied function...')
await target.apply(thisArg, argumentsList)
console.log('PROXY: setting load to false...')
thisArg.loading = false
}
}
MyObj.prototype.asyncLoad = new Proxy(asyncLoad, handler);
async function run() {
let myobj = new MyObj()
console.log(`in run, before calling someAsyncFunction, loading = ${myobj.loading}`)
setTimeout(() => {
console.log(`INTERRUPT: checking loading is true (${myobj.loading})`)
}, 500)
await myobj.someAsyncFunction(1)
console.log(`in run, after calling someAsyncFunction, loading = ${myobj.loading}`)
}
run()
选择性代理
如果您尝试调用的函数足够通用,以至于您有时只需要执行代理操作,那么这是完全可行的。这也是Proxy非常酷的地方,因为您可以创建不同的代理来执行不同的操作,同时保持相同的基本代码。
在下面的示例中,asyncLoad是我的通用函数,我可以call将它提供一个实例ObjWithoutStatus作为函数的this上下文。但我也创建了两个代理,一个用于设置loading状态,另一个用于设置loaderIsRunning状态。这些中的每一个最终都会调用基本函数,而不必执行创建维护正确范围的包装器的体操。
class ObjWithoutStatus {
constructor() {}
}
class ObjWithLoading {
constructor() {
this.loading = false
}
}
class ObjWithLoaderIsRunning {
constructor() {
this.loaderIsRunning = false
}
}
async function asyncLoad(params) {
return new Promise(resolve => {
console.log(`entering asyncLoad: loading = ${this.loading}, value = ${params.value}`)
setTimeout(() => {
console.log(`exiting asyncLoad: loading = ${this.loading}, value = ${params.value}`)
resolve()
}, 1000)
})
}
const handler_loading = {
apply: async function(target, thisArg, argumentsList) {
console.log('PROXY_loading: setting load to true...')
thisArg.loading = true
console.log('PROXY_loading: calling the proxied function...')
await target.apply(thisArg, argumentsList)
console.log('PROXY_loading: setting load to false...')
thisArg.loading = false
}
}
const handler_loaderIsRunning = {
apply: async function(target, thisArg, argumentsList) {
console.log('PROXY_loaderIsRunning: setting load to true...')
thisArg.loaderIsRunning = true
console.log('PROXY_loaderIsRunning: calling the proxied function...')
await target.apply(thisArg, argumentsList)
console.log('PROXY_loaderIsRunning: setting load to false...')
thisArg.loaderIsRunning = false
}
}
const asyncLoad_loading = new Proxy(asyncLoad, handler_loading)
const asyncLoad_loaderIsRunning = new Proxy(asyncLoad, handler_loaderIsRunning)
const x = new ObjWithoutStatus()
const y = new ObjWithLoading()
const z = new ObjWithLoaderIsRunning()
async function run() {
console.log(`in run, before calling asyncLoad, x.loading, x.loaderIsRunning = ${x.loading}, ${x.loaderIsRunning}`)
setTimeout(() => console.log(`INTERRUPT_asyncLoad: x.loading, x.loaderIsRunning = ${x.loading}, ${x.loaderIsRunning}`), 500)
await asyncLoad.call(x, {
value: 1
})
console.log(`in run, after calling asyncLoad, x.loading, x.loaderIsRunning = ${x.loading}, ${x.loaderIsRunning}`)
console.log(`in run, before calling asyncLoad_loading, y.loading = ${y.loading}`)
setTimeout(() => console.log(`INTERRUPT_asyncLoad_loading: y.loading = ${y.loading}`), 500)
await asyncLoad_loading.call(y, {
value: 2
})
console.log(`in run, after calling asyncLoad_loading, y.loading = ${y.loading}`)
console.log(`in run, before calling asyncLoad_loaderIsRunning, z.loaderIsRunning = ${z.loaderIsRunning}`)
setTimeout(() => console.log(`INTERRUPT_asyncLoad_loading: z.loaderIsRunning = ${z.loaderIsRunning}`), 500)
await asyncLoad_loaderIsRunning.call(z, {
value: 3
})
console.log(`in run, after calling asyncLoad_loaderIsRunning, z.loaderIsRunning = ${z.loaderIsRunning}`)
}
run()