节点代码不阻塞?
Node code not blocking?
我有一个构造函数,它使用 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
是未定义的。我该如何解决这个问题?
谢谢,我正在艰难地学习 node 和 typescript :O
您通常不想在构造函数中执行异步操作,因为这会使创建对象变得复杂,然后知道异步操作何时完成或是否有错误,因为您需要允许构造函数 return 对象,而不是在异步操作完成时告诉您的承诺。
有几种可能的设计方案:
选项 #1:不要在构造函数中执行任何异步操作。 然后,添加一个具有适当名称的新方法来执行异步操作,并且 return是一个承诺。
在您的情况下,您可以使新方法成为 scan()
return 的承诺。然后,您可以通过创建对象来使用您的对象,然后调用扫描,然后使用 returned 承诺知道数据何时有效。
我自己不了解 TypeScript,因此我将提供您代码的修改版本,但无论是 TypeScript 还是纯文本,概念都是相同的 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:在构造函数中启动异步操作,并在实例数据中使用一个 promise,以便调用者知道一切何时完成。
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:使用 return 解析为对象本身的承诺的工厂函数。
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。它捕获工厂函数中的一些共享代码,每个调用者都必须在其他方案中执行这些代码。它还会阻止访问对象,直到它被正确初始化。其他两个方案只需要文档和编程纪律,很容易被滥用。
我有一个构造函数,它使用 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
是未定义的。我该如何解决这个问题?
谢谢,我正在艰难地学习 node 和 typescript :O
您通常不想在构造函数中执行异步操作,因为这会使创建对象变得复杂,然后知道异步操作何时完成或是否有错误,因为您需要允许构造函数 return 对象,而不是在异步操作完成时告诉您的承诺。
有几种可能的设计方案:
选项 #1:不要在构造函数中执行任何异步操作。 然后,添加一个具有适当名称的新方法来执行异步操作,并且 return是一个承诺。
在您的情况下,您可以使新方法成为 scan()
return 的承诺。然后,您可以通过创建对象来使用您的对象,然后调用扫描,然后使用 returned 承诺知道数据何时有效。
我自己不了解 TypeScript,因此我将提供您代码的修改版本,但无论是 TypeScript 还是纯文本,概念都是相同的 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:在构造函数中启动异步操作,并在实例数据中使用一个 promise,以便调用者知道一切何时完成。
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:使用 return 解析为对象本身的承诺的工厂函数。
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。它捕获工厂函数中的一些共享代码,每个调用者都必须在其他方案中执行这些代码。它还会阻止访问对象,直到它被正确初始化。其他两个方案只需要文档和编程纪律,很容易被滥用。