Javascript承诺等待结果

时间:2019-02-06 09:02:28

标签: javascript reactjs promise

我正在开发一个React应用程序,该应用程序将通过ADAL与Azure广告进行身份验证。一切正常,但我需要在应用程序的开头加载JWT令牌。我以为我会包装我的两个函数,这些函数会在Promise中返回一个令牌,然后有条件地呈现它,但是由于某种原因,它不会“等待”我的承诺解决。

任何帮助都将受到欢迎。干杯!

import React, { Component } from 'react';

import { library } from '@fortawesome/fontawesome-svg-core';
import { faIgloo, faBars } from '@fortawesome/free-solid-svg-icons';
import { initializeIcons } from '@uifabric/icons';
import { acquireToken, acquireGraphToken } from '../../adalConfig'

import Navbar from '../../common/navbar/navbar';
import Searchbar from '../../common/utils/searchBar/searchBar';
import LeftNavigation from '../../common/leftNavigation/leftNavigation';
import PageContainer from '../pageContainer/pageContainer';
import { IntlProvider } from 'react-intl';

import messages_en from '../../assets/translations/translations_en';
import messages_nl from '../../assets/translations/translations_nl';
import StylesheetLoader from '../../common/utils/stylesheetLoader/stylesheetLoader';
import ReactAI from 'react-appinsights';
import { connect } from 'react-redux';
import * as userActions from '../../store/users/actions';

initializeIcons();
library.add(faIgloo, faBars);

class App extends Component {

  state = {
    languageChoice: 'en',
    theme: 'red',
    tokensAreLoaded: false
  }

  componentWillMount() {

    let promise = new Promise((resolve, reject) => {
      const token = acquireToken();
      const graphToken = acquireGraphToken();

      if (token != '' && graphToken != '') {
        resolve(true);
      } else {
        reject(Error('promise failed'))
      }
    });

    promise.then( (value) => {
      this.setState({tokensAreLoaded: value});
    }, function (error){
      console.log('error getting promise value');
    })
  }

  componentDidMount() {
    this.props.onFetchCurrentUser();
  }    

  render() {

    if (this.state.tokensAreLoaded) {
      console.log('renderApp');
    } else {
      console.log('loading');
    }

    // Sets an interval that refreshes to get the token every 15 minutes
    // We use this because our custom API's do not automatically issue a
    // refresh token.
    setInterval(AppTokenRefresher, 900000);

    function AppTokenRefresher() {
      acquireToken();
      acquireGraphToken();
    } 

    const messages = {
        'nl': messages_nl,
        'en': messages_en
    };

    ReactAI.setAppContext({urlReferrer: document.referrer});
    // const Ai = ReactAI.ai();

    // function test() {
    //   Ai.trackEvent('Testing', { 'user': 'me' });
    // }

    const user = this.props.currentUser ? this.props.currentUser.name : 'test';

    return (
      <React.Fragment>
        <StylesheetLoader />
        {user}
        <IntlProvider locale={this.state.languageChoice} messages={messages[this.state.languageChoice]}>
          <div className="siteContainer">
            <Navbar currentUserProfile={this.props.currentUser}></Navbar>

            <div className="mobile-searchbar">
              <Searchbar />
            </div>

            <div className='page-container'>
              <aside>
                <LeftNavigation />
              </aside>

              <section className="main">
                <PageContainer />
            </section>

            </div>

          </div>
        </IntlProvider>

      </React.Fragment>
    );
  }
}

const mapStateToProps = state => {
  return {
      currentUserError: state.currentUserSlice.currentUserError,
      currentUserLoading: state.currentUserSlice.currentUserLoading,
      currentUser: state.currentUserSlice.currentUser,
      currentUserPicture: state.currentUserSlice.currentUserPicture
  }
}

const mapDispatchToProps= (dispatch) => {
  return {
      onFetchCurrentUser: () => dispatch(userActions.fetchCurrentUser()),
      onFetchCurrentUserPicture: () => dispatch(userActions.fetchCurrentUserPicture())
  }    
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

我在承诺中包含的adal辅助函数:

import { AuthenticationContext, adalFetch } from 'react-adal';

const adalConfig = {
    instance: 'https://login.microsoftonline.com/',
    clientId: '9e16003a',
    extraQueryParameter: 'nux=1',
    endpoints: {
        graphApi: 'https://graph.microsoft.com',
        oneApi: 'https://one365demo.onmicrosoft.com/b15a-3f1d0cf658f5'
    },
    postLogoutRedirectUri: window.location.origin,
    redirectUri: window.location.origin,
    cacheLocation: 'localStorage'
};

export const authContext = new AuthenticationContext(adalConfig);



export const adalGraphFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.graphApi, fetch, url, options);

export const adalOneApiFetch = (fetch, url, options) =>
  adalFetch(authContext, adalConfig.endpoints.oneApi, fetch, url, options);

export const getToken = () => {
    return authContext.getCachedToken(authContext.config.clientId);
};

export const getGraphToken = () => {
    return authContext.getCachedToken('https://graph.microsoft.com');
};

export const acquireGraphToken = () => {  
    authContext.acquireToken(adalConfig.endpoints.graphApi, (message, token, msg) => {
        console.log('graph token', token);
        return token;
    })

    return null;
} 

export const acquireToken = () => {  
    authContext.acquireToken(adalConfig.endpoints.oneApi, (message, token, msg) => {
        console.log('the token', token);
        return token;
    })

    return null;
}

2 个答案:

答案 0 :(得分:3)

AuthenticationContext#acquireToken似乎是一个异步方法,它具有一个回调,该回调在获取令牌时(或尝试失败时)被调用。

请考虑重新定义将acquireToken()括起来的adal helper方法,以使它们成为async,或者使它们返回Promise,该回调在回调传递给{{ 1}}被调用:

AuthenticationContext#acquireToken()

在帮助程序模块中应用了这些更改之后,您需要更新export const acquireGraphToken = () => { /* Return promise as acquireToken() is async */ return (new Promise(resolve => { authContext.acquireToken(adalConfig.endpoints.graphApi, (message, token, msg) => { console.log('graph token', token); /* Resolve enclosing promise with token */ resolve(token); }) })); } export const acquireToken = () => { /* Return promise as acquireToken() is async */ return (new Promise(resolve => { authContext.acquireToken(adalConfig.endpoints.oneApi, (message, token, msg) => { console.log('the token', token); /* Resolve enclosing promise with token */ resolve(token); }) })); } 组件挂钩以正确集成这些方法,以确保一旦两个令牌都被使用,则componentWillMount()会更新组件状态。成功获取:

{tokensAreLoaded: true}

希望这会有所帮助!

答案 1 :(得分:0)

我建议引入某种加载通知,直到获取令牌为止。您可以等待componentDidMount中的令牌,以免阻塞堆栈

async componentDidMount() {
    try {
        const token = await this.getToken();
        this.setState({tokensAreLoaded: true, token});
    } catch (e) {
        throw new Error (e);
    }
}
getToken () {
    return new Promise((resolve, reject) => {
        const token = acquireToken();
        const graphToken = acquireGraphToken();

        if (token != '' && graphToken != '') {
            resolve(token);
        } else {
           reject(Error('promise failed'))
        }
    });
}

在您的render方法中:

render () {
    if (!this.state.tokensAreLoaded) {
        return (<p>Authorizing</p>);
    }
    return (
       // the stuff you want to display when token is ready
    )

}