Код узла не блокируется?

У меня есть конструктор, который выбирает данные из 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, а затем используя возвращенное обещание, чтобы узнать, когда данные действительны.

Я сам не знаю 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: Инициируйте асинхронную операцию в конструкторе и используйте обещание в данных экземпляра, чтобы вызывающая сторона знала, когда все сделано.

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 по нескольким причинам. Он фиксирует некоторый общий код в заводской функции, который каждый вызывающий должен делать в других схемах. Это также предотвращает доступ к объекту, пока он не будет правильно инициализирован. Две другие схемы просто требуют документации и дисциплины программирования и могут легко использоваться неправильно.

Другие вопросы по тегам