web-dev-qa-db-ja.com

飲み込まれたメッセージ:エラー:キャッチされていません(約束されています):[オブジェクトが未定義]

ログインコンポーネントは、promiseの未定義のオブジェクトに関するエラーメッセージによって削除される前に、簡単に表示されます。

これが約束の定義です:

_  static init(): Promise<any> {
    KeycloakClientService.auth.loggedIn = false;
    return new Promise((resolve, reject) => {
      const keycloakConfig = {
      url: environment.KEYCLOAK_URL,
      realm: environment.KEYCLOAK_REALM,
      clientId: environment.KEYCLOAK_CLIENTID,
      'ssl-required': 'external',
      'public-client': true
      };
      const keycloakAuth: any = new Keycloak(keycloakConfig);

      keycloakAuth.init({onLoad: 'check-sso'})
        .success(() => {
          KeycloakClientService.auth.loggedIn = true;
          KeycloakClientService.auth.authz = keycloakAuth;
          KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
          + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
          + document.baseURI;
          console.log('=======>> The keycloak client has been initiated successfully');
          resolve('Succeeded in initiating the keycloak client');
        })
        .error(() => {
          reject('Failed to initiate the keycloak client');
        });
    });
  }
_

それは次のように呼ばれます:

_KeycloakClientService.init()
  .then(
    () => {
      console.log('The keycloak client has been initialized');
    }
  )
  .catch(
    (error) => {
      console.log(error);
      window.location.reload();
    }
  );
_

コンソールには両方のメッセージが表示されます。

_The keycloak client has been initiated successfully
The keycloak client has been initialized
_

私はAngular _6.0.4_を使用しており、これを試してみました blog

ログインフォームを表示したままにするために、このエラーを回避する方法はありますか?

更新:私は約束の代わりにオブザーバブルを使用しようとしましたが、問題は同じままでした:

_  public init(): Observable<any> {
    KeycloakClientService.auth.loggedIn = false;
    return new Observable((observer) => {
      const keycloakConfig = {
        'url': environment.KEYCLOAK_URL,
        'realm': environment.KEYCLOAK_REALM,
        'clientId': environment.KEYCLOAK_CLIENTID,
        'ssl-required': 'external',
        'public-client': true
      };
      const keycloakAuth: any = new Keycloak(keycloakConfig);

      keycloakAuth.init({ 'onLoad': 'check-sso' })
        .success(() => {
          KeycloakClientService.auth.loggedIn = true;
          KeycloakClientService.auth.authz = keycloakAuth;
          KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
            + document.baseURI;
          console.log('The keycloak auth has been initialized');
          observer.next('Succeeded in initiating the keycloak client');
          observer.complete();
        })
        .error(() => {
          console.log('The keycloak client could not be initiated');
          observer.error('Failed to initiate the keycloak client');
        });
    });
  }
_

ソースコード全体は GitHub で入手できます。

更新:以下の回答に続いて、then()およびcatch()キーワードも使用しようとしましたが、エラーはまったく同じままでした:

_keycloakAuth.init({ 'onLoad': 'check-sso' })
        .then(() => {
          KeycloakClientService.auth.loggedIn = true;
          KeycloakClientService.auth.authz = keycloakAuth;
          KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
            + document.baseURI;
          console.log('The keycloak auth has been initialized');
          observer.next('Succeeded in initiating the keycloak client');
          observer.complete();
        })
        .catch(() => {
          console.log('The keycloak client could not be initiated');
          observer.error('Failed to initiate the keycloak client');
        });
_
10
Stephane

これはワイルドな推測ですが、おそらくAngularのゾーンとの競合です。これはセキュリティライブラリなので、Angularはコア関数をプロキシに置き換えました。たとえば、NgZonewindow.setTimeoutとHTTPメソッドを変更します。

したがって、ゾーンの外でこのコードを実行してみることができます。ここでの唯一の問題は、static関数を使用していることであり、これをNgZoneにアクセスできるようにインジェクタブルサービスにする必要があります。

@Injectable()
export class KeycloakClientService {
    public constructor(private zone: NgZone) {
    }

    public init(): Promise<any> {
        KeycloakClientService.auth.loggedIn = false;
        return new Promise((resolve, reject) => {
            this.zone.runOutsideAngular(() => {
                const keycloakConfig = {
                     url: environment.KEYCLOAK_URL,
                     realm: environment.KEYCLOAK_REALM,
                     clientId: environment.KEYCLOAK_CLIENTID,
                     'ssl-required': 'external',
                     'public-client': true
                };

                const keycloakAuth: any = new Keycloak(keycloakConfig);

                keycloakAuth.init({onLoad: 'check-sso'})
                    .success(() => {
                        KeycloakClientService.auth.loggedIn = true;
                        KeycloakClientService.auth.authz = keycloakAuth;
                        KeycloakClientService.auth.logoutUrl = environment.KEYCLOAK_URL
                            + '/realms/' + environment.KEYCLOAK_REALM + '/protocol/openid-connect/logout?redirect_uri='
                            + document.baseURI;
                        console.log('=======>> The keycloak client has been initiated successfully');
                        resolve('Succeeded in initiating the keycloak client');
                    })
                    .error(() => {
                        reject('Failed to initiate the keycloak client');
                    });
            });
        }
    }
}

ここでの変更はzone.runOutsideAngularを使用することです

3
Reactgular

successブロックを削除した場合、success内のロジックをどこで実行しますか?

私は彼らのソースコードのいくつかを読みました、これがsuccessが問題を引き起こす理由だと思います:

_keycloak.js_内には、関数createNativePromise()があります。

_function createNativePromise() {
var p = {
    setSuccess: function(result) {
        p.success = true;
        p.resolve(result);
    },

    setError: function(result) {
        p.success = false;
        p.reject(result);
    }
};
p.promise = new Promise(function(resolve, reject) {
    p.resolve = resolve;
    p.reject = reject;
});
p.promise.success = function(callback) {
    p.promise.then(callback);
    return p.promise;
}
p.promise.error = function(callback) {
    p.promise.catch(callback);
    return p.promise;
}
return p;
}
_

そして、それはこのように使用されます(簡略化されたコード):

_function refreshToken() {
    var promise = createNativePromise();
    ...
    if (refreshTokenFailed) {
        promise.setError(true);
    }
    ...

    return promise.promise;
}
_

問題は、promise.setError()promise.reject(result)を呼び出すため、プロミスが拒否され、catchが期待されます。

しかし、_promise.success_内にはpromise.promise.then(callback);があり、誰もこの約束をつかんでいません。

これがUncaught (in promise): [object Undefined]を取得する理由です。私の場合、私は常にUncaught (in promise): trueを取得します。

解決:

_promise.promise_は実際のPromiseであるため、thenおよびcatchの代わりにsuccessおよびerrorを使用できます。

欠点は、TypeScriptタイプが間違っていることです。

0
penghui