#angular #typescript #ionic-framework
#angular #typescript #ionic-framework
Вопрос:
Пожалуйста, простите ошибку noobie, я пытаюсь использовать Ionic, исходящий из фона C #, так что это может быть частью проблемы. Я пытаюсь получить сохраненный токен из ионного хранилища, но изо всех сил пытаюсь разобраться в обещаниях и.затем so решил использовать ‘await’, так как я привык к этому в c #.
Это часть Api-сервиса, который я хочу создать, поэтому мне нужно привести в порядок мои http-заголовки, и поэтому в конструкторе я извлекаю токен, чтобы добавить его. Вот раздел файла TS службы Api:
export class ApiService {
ServerUrl = environment.url;
BearerToken: string;
GetUserDetailsEndPoint = 'api/Account/GetUserDetails';
UpdateUserDetailEndPoint = 'api/Account/UpdateUserDetail';
TokenEndPoint = 'Token';
RegisterEndPoint = 'api/Account/Register';
httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'bearer ' this.BearerToken
})
};
constructor( private http: HttpClient,
private storage: Storage,
private alertController: AlertController ) {
this.getBearerToken(); // I put this in a function cos not sure how the async stuff plays out in a constructor
console.log('Have awaited the token and its value is:' this.BearerToken);
}
async getBearerToken() {
this.BearerToken = await this.storage.get(TOKEN_KEY);
}
Итак, довольно просто: «это.BearerToken’ не определен при отправке на консоль. (Значение действительно существует в хранилище).
Очевидно, что это какая-то проблема асинхронного типа, но я изо всех сил пытаюсь понять, почему ‘await’ этого не делает ..?
Я довольно много читал, но в большинстве случаев люди используют .затем функциональность с обещаниями. Чего я здесь не понимаю?
Спасибо
РЕДАКТИРОВАТЬ Следуя совету Игоря здесь, я переношу инициализацию из UserService в ngOnInit моей страницы меню, где мне сначала нужно ее использовать. Я нахожусь в той же области получения информации о пользователе из локального хранилища, а не токена, но это та же проблема. Так что, я думаю, я все еще чего-то не понимаю… функция для получения сохраненного пользователя заключается в следующем:
async getUserStore() { // Populate the data object with the stored info
this.data = await this.storage.get(USER_DATA);
console.log('getUserStore: email = ' this.data.Email);
}
где это.данные — это объект UserData внутри класса service.
Однако эта функция по-прежнему возвращает обещание, а не ожидает перед возвратом. Нужно ли мне заставить его возвращать что-то конкретное, чтобы ожидание действительно ожидало? например
return await this.storage.get(USER_DATA);
или используйте .затем подойдите, и если да, то какой смысл вообще «ждать» этого?
Моя вызывающая функция выглядит следующим образом: (чтобы работать должным образом)
ngOnInit() {
this.user.getUserStore().then(() => {
console.log('ngOnInit - menu page, this.user email is: ' this.user.data.Email);
if (this.user.data amp;amp; !this.user.data.DetailsComplete) {
this.showAlert('Your Details are incomplete, please can you complete them?');
}
console.log('ngOnInit - menu page');
});
}
В то время как с await в асинхронной функции я ожидал бы, что это будет выглядеть следующим образом: (что не работает)
ngOnInit() {
this.user.getUserStore();
console.log('ngOnInit - menu page, this.user email is: ' this.user.data.Email);
if (this.user.data amp;amp; !this.user.data.DetailsComplete) {
this.showAlert('Your Details are incomplete, please can you complete them?');
}
console.log('ngOnInit - menu page');
}
Итак, как (используя await) я мог бы заставить его действительно ждать в вызываемой функции? или я не могу? Приветствия
Комментарии:
1. Вы не ожидаете вызова
this.getBearerToken();
в конструкторе. Вам не следует выполнять асинхронные действия в конструкторах по другим причинам, но именно поэтому это еще не сделано.
Ответ №1:
Не выполняйте async/await
вызовы в a constructor
, поскольку конструкторы не поддерживают async/await
ключевые слова. Если вы хотите использовать async/await
, вы должны убедиться, что все Promise
ожидаются или разрешаются с помощью таких методов, как then()
и, если вы используете async/await
метод с await
вызовами, подпись которого имеет префикс async
.
Один из недостатков дизайна, связанных с размещением «сложной» логики в конструкторе, заключается в том, что ваш тип становится сложным для модульного тестирования. Другой, в этом случае, заключается в том, что вы не можете использовать ключевое слово await
, потому что вы не можете пометить конструктор как async
.
Вариант 1 — предоставить новый метод, помеченный как async / await
constructor( private http: HttpClient,
private storage: Storage,
private alertController: AlertController ) {}
async initialize() {
await this.getBearerToken();
console.log('Have awaited the token and its value is:' this.BearerToken);
}
async getBearerToken() {
this.BearerToken = await this.storage.get(TOKEN_KEY);
}
Вариант 2 — используйте стандартный метод promise, подобный then
constructor( private http: HttpClient,
private storage: Storage,
private alertController: AlertController ) {}
initialize() {
this.getBearerToken().then(_ => console.log('Have awaited the token and its value is:' this.BearerToken));
}
async getBearerToken() {
this.BearerToken = await this.storage.get(TOKEN_KEY);
}
Редактировать
Я собираюсь предположить, что вы хотите это для компонента или директивы. Вам нужно только реализовать OnInit
с помощью метода ngOnInit
в вашем компоненте или директиве. Именно туда вам следует поместить код, который вы хотите запустить при создании вашего компонента.
export class MyComponent implements OnInit {
myBearerToken: any;
constructor(private service: AuthService) { }
async ngOnInit() {
this.myBearerToken = await this.service.getBearerToken();
}
}
В качестве альтернативы вы также можете выполнить этот же вызов, используя then
даже если то, что вы вызываете, использует async/await
.
Правка 2
В вашем последнем примере того, как вы хотите изменить на await, вы никогда не использовали await или async. Это должно быть:
async ngOnInit() {
await this.user.getUserStore();
// rest of code
Комментарии:
1. Спасибо, Игорь и JBC, хорошо, так что не вызывайте асинхронные функции в конструкторе, это то, что вы говорите, но перенос его в другую асинхронную функцию не помогает, если мне нужно получить токен хранилища в конструкторе. Функция хранения — это ионная библиотека, которая является асинхронной, поэтому я не могу это контролировать. Итак, могу я спросить, что, если вообще что-либо, я должен сделать, чтобы вызвать функцию инициализации изнутри конструктора … или, на самом деле, как мне получить доступ к сохраненному токену. Я имею в виду, я думаю, у меня мог бы быть какой-то сервис ‘startup’, который делает сохраненные данные доступными в виде глобальных файлов или что-то в этом роде? т. Е. найдите другой способ 🙂
2. @BrettJB — Смотрите правку, которую я добавил к ответу. Если это не то, что вы ищете, вам нужно сообщить нам, как вы хотите получить информацию, каков фактический потребитель, потому что сервисы не работают сами по себе.
3. Да, это сработает, и я собираюсь отметить как ответ, потому что вы были достаточно любезны, чтобы помочь мне. Я думаю, моя ошибка в том, что я знаю, на каких уровнях находится компонент, служба и т.д. и где они все подходят. Проблема с попыткой выучить слишком много вещей одновременно — Angular, Typscript, Ionic… Еще раз спасибо, Бретт
4. Типичный шаблон заключается либо в извлечении значения в другом месте и передаче его конструктору, либо в использовании метода «инициализации», который вызывается асинхронно. Это идет рука об руку с отображением пользователю какого-либо индикатора «выполняется», такого как счетчик загрузки.
5. Еще раз привет, Игорь, я внес правку в свой вопрос, которая, как мне кажется, более точно демонстрирует мою проблему. Интересно, не могли бы вы указать мне место, где это лучше объясняется? Еще раз спасибо…