2016-04-28 14 views
0

下面我有一個main函數。這個函數有許多其他變量聲明並運行許多函數。如果在函數內發生錯誤,我可以捕獲這個錯誤,但在我的捕獲中,我沒有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

簡單的解決方案是使用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

您可能仍然希望'try'內的第一個'await',以防萬一失敗 - 只需在外部範圍聲明'operation' var。 – nrabinowitz

+0

@nrabinowitz:不,我真的打算把第一個'await'放在內部'try'的外面,這樣異常/拒絕就會被外部'catch'塊捕獲。當然,皮膚貓有很多種方法,這可能或可能不是真正需要的。 – Bergi

+0

@Bergi這個想法是,即使doSomethingElse拋出一個錯誤,我也想訪問'one'的值。 – ThomasReggi

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]) 
    }) 

})