【问题标题】:UnhandledPromiseRejectionWarning: Unhandled promise rejection Error on CRA Universal appUnhandledPromiseRejectionWarning:CRA Universal 应用程序上出现未处理的承诺拒绝错误
【发布时间】:2021-05-02 02:03:14
【问题描述】:

我有使用 cra-universal 库制作的通用应用程序,当服务器没有收到 api 响应时,ssr 服务器停止并中断页面。我得到的错误是 UnhandledPromiseRejectionWarning: Unhandled Promise Rejection。此错误源于在没有 catch 块的情况下抛出异步函数内部,或拒绝未在 .catch() 中处理的承诺。要在未处理的 Promise 拒绝时终止节点进程,请使用 CLI 标志 --unhandled-rejections=strict

下面是我来自 cra-universal 的 ssr 服务器代码。


// import thunk from 'redux-thunk';
import { createReactAppExpress } from '@cra-express/core';
import { getInitialData } from '@cra-express/router-prefetcher';
import { HelmetProvider } from 'react-helmet-async';

// import Cookies from 'cookies';
import { getStoredState, persistCombineReducers } from 'redux-persist';
// import { CookieStorage, NodeCookiesWrapper } from 'redux-persist-cookie-storage';
import autoMergeLevel1 from 'redux-persist/lib/stateReconciler/autoMergeLevel1';
import storage from "redux-persist/lib/storage";
// import StyleContext from 'isomorphic-style-loader/StyleContext'
import routes from '../src/routes';
import {store} from '../src/index'
import {ChunkExtractor,ChunkExtractorManager} from '@loadable/server'
const path = require('path');
const React = require('react');
const { Provider } = require('react-redux');
const { StaticRouter } = require('react-router-dom');
const { createStore, applyMiddleware ,compose} = require('redux');

const { default: App } = require('../src/App');
const { default: reducer } = require('../src/redux/reducers');
const clientBuildPath = path.resolve(__dirname, '../client');
const statsFile=path.resolve(__dirname,'../dist/loadable-stats.json')
let tag = '';
//let store;
let AppClass = App;
let serverData;
let helmetCtx;
// console.log("REDUCERS",reducer)
const app = createReactAppExpress({
  clientBuildPath,
  universalRender: handleUniversalRender,
  async onFinish(req, res, html) {
    const { helmet } = helmetCtx;
    const helmetTitle = helmet.title.toString();
    const helmetMeta = helmet.meta.toString();
    const newHtml = html
      .replace('{{HELMET_TITLE}}', helmetTitle)
      .replace('{{HELMET_META}}', helmetMeta);
    res.send(newHtml);
  },
  onEndReplace(html) {
    const state = store.getState();
  //console.log("----SERVER getState----", store.getState());

    return html.replace(
      '{{SCRIPT}}',
      `${tag}<script>
      window.__PRELOADED_STATE__ = ${JSON.stringify(state).replace(
        /</g,
        '\\u003c'
      )};
      window.__INITIAL_DATA__ = ${JSON.stringify(serverData).replace(
        /</g,
        '\\u003c'
      )};
    </script>`
    );
  }
});

function handleUniversalRender(req, res) {
  const context = {};
  helmetCtx = {};

  // const cookieJar = new NodeCookiesWrapper(new Cookies(req, res));

  const persistConfig = {
    key: 'root',
    storage: storage,
    // storage: new CookieStorage(cookieJar),
    stateReconciler: autoMergeLevel1,
    // stateReconciler(inboundState, originalState) {
    //     return originalState;
    // }
  };

  let preloadedState;

  getStoredState(persistConfig)
    .then(preloadedState => {
      //console.log("SERVER Preloded State", preloadedState);
    })

  try {
      preloadedState = {
        test: 'presisited Data'
      };
  } catch (e) {
      preloadedState = {};
  }

  const rootReducer = persistCombineReducers(persistConfig, reducer);

 /* store = createStore(
    rootReducer,
    preloadedState,
    applyMiddleware(thunk)
  );*/

  // console.log("----SERVER getState----", store.getState());
// console.log("getInitialData",getInitialData)
  return getInitialData(req, res,routes)
    .then(data => {

      const css = new Set();
      const insertCss = (...styles) => styles.forEach(style => css.add(style._getCss()));


      const extractor=new ChunkExtractor({statsFile})
      const scriptTags = extractor.getScriptTags()
      serverData = data;
      // console.log("CSS FILES", scriptTags);
      const app = (
        <HelmetProvider context={helmetCtx}>
          <StaticRouter location={req.url} context={context}>
            <Provider store={store}>
            {/* <StyleContext.Provider value={{ insertCss }}> */}
            <ChunkExtractorManager extractor={extractor}>
              <AppClass routes={routes} initialData={data} store={store}/>
            </ChunkExtractorManager>
            {/* </StyleContext.Provider> */}
            </Provider>
          </StaticRouter>
        </HelmetProvider>
      );

      if (context.url) {
        res.redirect(301, context.url);
        return;
      }
    
      return app;
       
    })
    .catch(err => {
      console.error(err);
      res.sendStatus(500);
    });
}

if (module.hot) {
  module.hot.accept('../src/App', () => {
    const { default: App } = require('../src/App');
    AppClass = App;
    console.log('✅ Server hot reloaded App');
  });
  module.hot.accept('../src/routes', () => {
    console.log('✅ Server hot reloaded routes');
  });
}

export default app;

有人可以帮我解决这个问题,因为我陷入困境并且必须尽早解决它。任何帮助或建议将不胜感激。

【问题讨论】:

    标签: javascript node.js reactjs promise server-side-rendering


    【解决方案1】:

    可以使用winston 处理未处理的异常、承诺拒绝和日志记录。如果您只需要处理 Promise 拒绝并且不想使用第三方工具,也可以使用现有的 process 变量来完成,例如:

    process.on('unhandledRejection', (ex) => {
        console.log('unhandledRejection caught:');
        console.log(ex.message);
    });
    
    // This will create an unhandled promise rejectin
    const p = Promise.reject(new Error('Failing with this promise..'));
    p.then(() => console.log('Done!')); // Note 'Done!' will never get printed
    

    注意:您必须在问题发生之前添加process.on(..),因为它为这些未处理的承诺拒绝添加了一个侦听器。在发生此拒绝的代码之后添加它不会捕获此未处理的拒绝。你应该把它放在代码顶部的某个地方,就在所有逻辑发生之前,例如:

    ...
    const { default: reducer } = require('../src/redux/reducers');
    
    process.on('unhandledRejection', (ex) => {
        console.log('unhandledRejection caught:');
        console.log(ex.message);
    });
    
    let tag = '';
    let AppClass = App;
    ...
    

    您同样可以使用关键字'uncaughtException' 捕获未捕获的异常。

    【讨论】:

    • 对不起,你能指出我在哪里以及如何使用它,因为我是新手,发现很难纠正这个问题。
    猜你喜欢
    • 2021-02-15
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-09
    相关资源
    最近更新 更多