【问题标题】:Node code not blocking?节点代码不阻塞?
【发布时间】:2018-01-08 19:00:29
【问题描述】:

我有一个构造函数,它使用承诺的 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

【问题讨论】:

    标签: node.js typescript dynogels


    【解决方案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:使用工厂函数,该函数返回解析为对象本身的承诺。

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

    【讨论】:

    • 感谢@jfriend00,它运行良好。虽然这段代码会阻塞createQueryAuthorizer 方法,而我的意图是对数据库进行异步调用,并且只在我第一次需要数据时等待,但只是第一次,因为数据将需要多次。不过,我会尝试更改实现。
    • @CarlosDelgado - 这里没有任何障碍,所以我不太清楚你的意思。 createQueryAuthorizer() 方法立即返回并返回一个承诺。在正确初始化之前,您不能使用您的对象。如果你的代码的其他部分也想使用同一个对象,他们可以等待同一个promise。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-18
    • 2015-12-03
    • 2020-09-22
    • 2012-07-26
    • 2015-11-25
    相关资源
    最近更新 更多