Лучший способ справиться с ошибками перехвата Promise, когда я иногда хочу, чтобы он молча провалился - PullRequest
0 голосов
/ 25 октября 2018

Я пишу приложение для Ionic, используя Ionic 4, и у меня возникают проблемы с выполнением моих Обещаний в правильном порядке (или, возможно, я просто думаю об этом неправильно).Я также впервые использую Typescript, так что терпите меня.

Приложению необходимо взаимодействовать с нашим API, который использует Oauth.Я храню токены Oauth с использованием ионного хранилища, которое также использует Promises для получения / установки, так что это добавляет к моей проблеме.

Если вы берете следующие фрагменты файла:

oauth.service.ts:

export class OauthService {

...    

    public async setTokens(token: string, token_secret: string) {
        return Promise.all([this.storage.set('token', token), this.storage.set('token_secret', token_secret)]);
    }

    public async getTokens() {
        return Promise.all([this.storage.get('token'), this.storage.get('token_secret')]);
    }

...

}

api.service.ts:

export class ApiService {

...

    public async getCustomer() {
        const requestData = {
            .. request data ..
        };

        return this.authorisedRequest(requestData);
    }

    private authorisedRequest(requestData) {
        return this.oauth.getTokens().then(([token, token_secret]) => {

            if (!token || !token_secret) {
                return Promise.reject('Tokens not available');
            }

            const tokens = {
                'key': token,
                'secret': token_secret
            };

            const oauthHeader = this.oauth.createHeader(requestData, tokens);
            const headers = this.createHeaders({
                'Authorization': oauthHeader.Authorization
            });

            return this.apiRequest(requestData.method, requestData.url, {}, headers);

        }).catch((error) => {
            // @todo what to do here, if anything?
            console.info('token error:', error)
        });
    }

    private async apiRequest(type, path, data, headers = null) {
        if (!headers) {
            headers = this.headers;
        }

        const response = new Subject();
        const httpRequest = new HttpRequest(
            type,
            path,
            data,
            {
                headers: headers
            }
        );

        this.http.request(httpRequest).subscribe((res: any) => {
            if (res.type) {
                response.next(res.body);
            }
        }, error => {
            const responseError = error.error.messages.error[0];
            this.alerter.presentAlert(responseError.message);

            response.error(error);
        });

        return response;
    }

}

authentication.service.ts:

export class AuthenticationService {

...

    public checkAuth() {
        this.api.getCustomer().then((request: Subject<any>) => {

           // this still executes but request is undefined.

            request.subscribe((resp: any) => {
                this.isLoggedIn = true;
            }, (error) => {
                this.isLoggedIn = false;
            });
        });
    }

...

}

По большей части это работает нормально,во всех случаях, когда токен существует, так как обещание не отклонено.

Однако, когда я запускаю checkAuth () для init (чтобы проверить, уже вошел ли пользователь), обещание getTokens () возвращает отклонение, котороесразу же перехватывается (в api.service), но внутри checkAuth по-прежнему выполняется 'then', хотя он должен был быть перехвачен, что выдает ошибку:

TypeError: Cannot read property 'subscribe' of undefined

IМожно переместить блок catch внутрь функции checkAuth, но это будет означать, что мне придется делать это во всех случаях, когда я выполняю вызов API (~ 30 нечетных конечных точек), что не идеально.

Без перехватов я получаю эту ошибку:

Uncaught (in promise): Tokens not available

Как я могу либо заставить отказ отклониться молча, либо, возможно, просто передать ошибку по checkAuth?

Или я иду по этому процессу совершенно неправильно?У меня есть ощущение, что мой процесс получения токена oauth здесь неправильный (вызывая вложенные обещания для любого вызова API).

1 Ответ

0 голосов
/ 25 октября 2018

Основная проблема в том, что вы смешиваете Observables с Promises неправильным образом.

Для простоты я предлагаю использовать только один из них одновременно.

Простое решение:

checkAuth() {
   this.api.getCustomer()
       .then((request: Subject<any>) => request.toPromise())
       .then(() => { this.isLoggedIn = true; })
       .catch(() => { this.isLoggedIn = false; });
}

или

import { from } from 'rxjs';

checkAuth() {
   const customersObservable = from(this.api.getCustomer());
   customersObservable.subscribe(
       () => { this.isLoggedIn = true; },
       () => { this.isLoggedIn = false; }
   );
}

Лучшее решение:

ИспользованиеОбещания или Observables на низком уровне, чтобы прояснить API вашего сервиса.

Пример с преобразованием Observables в Promises :

export class OauthService {
    public async getTokens(): Promise<any> { ... }
}

export class ApiService {
    public async getCustomers(): Promise<Customer> {
        ...
        return await this.authRequest(someRequest);
    }

    private async authorisedRequest(request) : Promise<any> {
        const [token, token_secret] = await this.oauth.getTokens();

        if (!token || !token_secret) {
            throw 'Tokens not available';
        }

        return await this.apiRequest(request);
    }

    private async apiRequest(request) : Promise<any> {
        const httpRequest = ...;
        // Here we are converting our Observable to a Promise to avoid mixing
        return await this.http.request(httpRequest)
            .toPromise();
    }
}

export class AuthenticationService {
    public async checkAuth() {
        try {
            await this.api.getCustomer();
            this.isLoggedIn = true;
        } catch {
            this.isLoggedIn = false;
        }
    }
}

Вы также можете использовать подход с Observable путем преобразования обещания в наблюдаемое (в общем случае код будет аналогичен примеру с обещаниями, поэтому я его пропускаю)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...