下面我有一个main
功能。此函数在其中声明了许多其他变量并运行许多函数。如果函数中发生错误,我可以捕获此错误,但在我的catch中,我没有main
函数的值。即使抛出错误,我也在寻找一种方法来访问所有变量。
export async function main ({alpha, beta, gamma}) {
let one = await doSomething(alpha)
let two = await doSomethingElse(one, beta)
return {one, two}
}
export async function store (db) {
await db.insert(data)
}
export async function usage (db, data) {
try {
let operation = await main(data)
await store (db, operation)
return operation
} catch (e) {
// here we don't have access to operation variables :(
await store(db, {}, e.message)
throw e
}
}
我发现这样做的唯一合理方法是创建一个类main
函数中的每个值。
import { get } from 'lodash'
export class Operation () {
constructor(db){
this.db = db
}
main({alpha, beta, gamma}) {
this.one = await doSomething(alpha)
this.two = await doSomethingElse(one, beta)
return {one: this.one, two: this.two}
}
init(data) {
try {
let main = await this.main(data)
await this.store(main)
return main
} catch (e) {
await this.store()
throw e
}
}
store(data = {}, errorMessage) {
if (!data.one) data.one = get(this, 'one') || null
if (!data.two) data.two = get(this, 'two') || null
if (errorMessage) data.errMessage = errorMessage
return await this.db.insert(data)
}
}
即使抛出错误,如何才能访问函数中的所有变量?
答案 0 :(得分:0)
简单的解决方案是使用var
声明一个函数作用域的变量,而不是一个作用于let
块的变量。
但是,你真的应该使用两个try
/ catch
语句,因为你试图捕获两个不同的错误并以不同的方式处理它们:
try {
let operation = await main(data)
try {
await store (db, operation)
} catch(e) {
// here we do have access to the `operation` variable :)
}
return operation
} catch (e) { // failed to create operation (or the inner catch did rethrow)
await store(db, {}, e.message)
throw e
}
答案 1 :(得分:0)
我创建了这个类和包装函数alwaysRunner
。它接受两个函数参数,并始终为辅助函数提供可用的变量。
export class AlwaysRunner {
constructor(operation, reguardless, optional = {}){
Object.assign(this, optional)
this.operation = operation.bind(this)
this.reguardless = reguardless.bind(this)
}
async init(data) {
let operation = this.operation
let reguardless = this.reguardless
let optional = this.optional
delete this.operation
delete this.reguardless
delete this.optional
try {
let main = await operation(data)
await reguardless(this)
return main
} catch (error) {
await reguardless({...this, error})
throw error
}
}
}
export async function alwaysRunner(operation, reguardless, optional) {
return await new AlwaysRunner(operation, reguardless, optional).init()
}
以下是一些测试方法。
describe('alwaysRunner', () => {
it('should work', async () => {
let ran = [false, false]
await alwaysRunner(function () {
ran[0] = true
this.alpha = true
this.beta = true
return this
}, function (values) {
ran[1] = true
assert.equal(values.alpha, true)
assert.equal(values.beta, true)
assert.equal(values.error, undefined)
}).should.not.be.rejected
assert.deepEqual(ran, [true, true])
})
it('should work with thrown error', async () => {
let ran = [false, false]
await alwaysRunner(function () {
ran[0] = true
this.alpha = true
throw new Error('some error')
this.beta = true
}, function (values) {
ran[1] = true
assert.equal(values.alpha, true)
assert.equal(values.beta, undefined)
assert.equal(values.error, new Error('some error'))
}).should.be.rejected
assert.deepEqual(ran, [true, true])
})
})