节点代码没有阻塞?

时间:2017-08-01 19:05:00

标签: node.js typescript dynogels

我有一个构造函数,它使用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 个答案:

答案 0 :(得分:1)

您通常不希望在构造函数中执行异步操作,因为它会使创建对象变得复杂,然后知道异步操作何时完成或者是否有错误,因为您需要允许构造函数返回对象,而不是在异步操作完成时会告诉你的承诺。

有几种可能的设计选择:

选项#1:不要在构造函数中执行任何异步操作。然后,添加一个具有相应名称的新方法,该方法执行异步操作并返回一个promise。

在您的情况下,您可以使新方法为scan(),以返回承诺。然后,您通过创建它然后调用scan然后使用返回的promise来知道数据何时有效来使用您的对象。

我自己并不知道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:使用工厂函数返回一个解析为对象本身的promise。

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 ,原因有几个。它捕获工厂函数中的一些共享代码,每个调用者必须在其他方案中执行这些代码。在正确初始化之前,它还会阻止对对象的访问。另外两个方案只需要文档和编程规则,很容易被滥用。