2017-08-01 46 views
-1

我有一個構造函數,它使用promisified dynogels從DynamoDB中獲取數據來填充對象屬性的一部分。 所以實例化對象的實例後,未填充屬性,這裏是代碼的摘錄:節點代碼是否阻塞?

export class QueryAuthoriser { 
    authPerms: [AuthPerms]; 

    constructor (data: string) { 
    AuthPermsDDB.scan().execAsync().then ((perms) => { 
     perms.Items.forEach(element => { 
     this.authPerms[element.name] = <AuthPerms> element.attrs 
     }) 
    }).catch (err => { 
     console.log ('%%%%%%%%%%%%%% Err loading authPerms: ', err) 
    }) 
    } 

    authFieldAccess (fieldName: string, args?:any): Promise<boolean> { 
    return new Promise ((resolve, reject) => { 
     console.log ('________________ authFieldAccess called for: ', fieldName) 
     console.log ('________________ this.authPerms entry: ', this.authPerms[fieldName]) 
     resolve (true) 
    }) 
[...] 
} 

所以當authFieldAccess方法被調用時,場this.authPerms是不確定的。我怎樣才能解決這個問題?

謝謝,我正在學習節點和打字稿硬盤的方式:o

回答

1

你一般不想在構造函數中進行異步操作,因爲它創建複雜的對象,然後知道當異步操作已完成,或者由於您需要允許構造函數返回對象而導致錯誤,而不是承諾會在異步操作完成時告訴您。

有幾種可行的設計方案:

選項#1:不要在構造函數中做任何異步操作。然後,添加一個具有適當名稱的新方法,該方法執行異步操作並返回承諾。

就你而言,你可以使新方法成爲scan()返回一個承諾。然後,通過創建它然後調用scan,然後使用返回的promise來知道數據何時有效,從而使用對象。

我不知道自己的打字原稿,所以我給你的代碼的修改版本,但概念是相同的兩種方式無論是打字稿或普通的JavaScript:

export class QueryAuthoriser { 
    authPerms: [AuthPerms]; 

    constructor (data: string) { 
    } 

    scan() { 
    return AuthPermsDDB.scan().execAsync().then ((perms) => { 
     perms.Items.forEach(element => { 
     this.authPerms[element.name] = <AuthPerms> element.attrs 
     }) 
    }).catch (err => { 
     console.log ('%%%%%%%%%%%%%% Err loading authPerms: ', err) 
    }) 
    } 

} 

// usage 
let obj = new QueryAuthoriser(...); 
obj.scan(...).then(() => { 
    // the object is full initialized now and can be used here 
}).catch(err => { 
    // error here 
}) 

選項#2 :在構造函數中啓動異步操作,並在調用者的實例數據中使用承諾,以瞭解何時完成所有事情。

export class QueryAuthoriser { 
    authPerms: [AuthPerms]; 

    constructor (data: string) { 
    this.initialScan = AuthPermsDDB.scan().execAsync().then ((perms) => { 
     perms.Items.forEach(element => { 
     this.authPerms[element.name] = <AuthPerms> element.attrs 
     }) 
    }).catch (err => { 
     console.log ('%%%%%%%%%%%%%% Err loading authPerms: ', err) 
    }) 
    } 

} 

// usage 
let obj = new QueryAuthoriser(...); 
obj.initialScan.then(() => { 
    // the object is full initialized now and can be used here 
}).catch(err => { 
    // error here 
}); 

選項#3:使用一個工廠函數,返回解析爲對象本身的承諾。

export createQueryAuthorizer; 

function createQueryAuthorizer(...) { 
    let obj = new QueryAuthorizer(...); 
    return obj._scan(...).then(() => { 
     // resolve with the object itself 
     return obj; 
    }) 
} 

class QueryAuthoriser { 
    authPerms: [AuthPerms]; 

    constructor (data: string) { 
    } 

    _scan() { 
    return AuthPermsDDB.scan().execAsync().then ((perms) => { 
     perms.Items.forEach(element => { 
     this.authPerms[element.name] = <AuthPerms> element.attrs 
     }) 
    }).catch (err => { 
     console.log ('%%%%%%%%%%%%%% Err loading authPerms: ', err) 
    }) 
    } 

} 

// usage 
createQueryAuthorizer(...).then(obj => { 
    // the object is fully initialized now and can be used here 
}).catch(err => { 
    // error here 
}); 

我的選擇是對選項#3有幾個原因。它捕獲工廠函數中的一些共享代碼,每個調用者必須在其他方案中執行該代碼。它也會阻止訪問對象,直到它被正確初始化。另外兩種方案只需要文檔和編程規則,很容易被濫用。

+0

謝謝@ jfriend00,它很好用。雖然這段代碼會阻塞'createQueryAuthorizer'方法,而我的意圖是對數據庫進行異步調用,並且只等待第一次需要數據時,但只是第一次,因爲數據將需要多次。不過,我會嘗試改變實現。 –

+0

@CarlosDelgado - 這裏沒有任何東西,所以我不太清楚你的意思。 'createQueryAuthorizer()'方法立即返回並返回一個promise。在正確初始化之前,您不能使用您的對象。如果代碼的其他部分也想使用同一個對象,他們可以等待相同的承諾。 – jfriend00