简体   繁体   中英

Properly catching a async function node.js

My attempt was:

my server.js has the following:

const app = express();
app.get('/*', loader(filePath, observer));

The file i'm trying to call sometimes loads with errors, which bubbles up to be uncaughtExceptions which restarts the server. I need to catch it in the catch{} somehow

export default (htmlFilePath, observer) => async (req, res) => {
    try {
      .......
      .......
      .......

        const markupStream = renderToNodeStream(
          <Provider store={store}>
            <ConnectedRouter history={history} location={context}>
              <App/>
            </ConnectedRouter>
          </Provider>
        );

        if (context.url) {
          return res.redirect(301, context.url)
        }

        return fs.createReadStream(htmlFilePath)
          .pipe(htmlReplace('#root', markupStream))
          .pipe(replaceStream('__SERVER_DATA__', serialize(store.getState())))
          .pipe(res);
      } catch (err) {
        const errMarkup = renderToNodeStream(
          <Provider store={store}>
            <ConnectedRouter history={history} location={context}>
              <Error500 error={err}/>
            </ConnectedRouter>
          </Provider>
        );

        logger.log({
          level: 'error',
          message: `Rendering ${req.originalUrl} fallback to Error render method`,
          ...{
            errorMessage: err.message,
            stack: err.stack
          }
        });

        return fs.createReadStream(htmlFilePath)
          .pipe(htmlReplace('#root', errMarkup))
          .pipe(res.status(500));
      } finally {
        logger.info(`Request finished ${req.originalUrl} :: ${res.statusCode}`)
        end({ route: path, componentName: componentNames[0], code: res.statusCode })
        logger.profile(profileMsg);
      }
}

What's the right way to do this? My issue before doing ().catch(err was that I always got uncaughtException , it did not ever go into the catch in the try{} catch{} within the function

When using an async express middleware, in order to catch any rejections and pass that rejection to the express error handler, you need a wrapper:

async-handler.js

const asyncHandler = fn => (req, res, next) => {
    return Promise
        .resolve(fn(req, res, next))
        .catch(next);
};

module.exports = asyncHandler;

ssr-stream.js

const ssrStream = (htmlFilePath, observer) => async (req, res) => {
    // If you wrap this middleware with asyncHandler
    // No need try/catch, you can let it bubble up, and it will go to express error middleware
    // Of course you can do it, and handle the custom error here, and let it bubble up for generic errors.
}

export default ssrStream;

index.js

const app = express();
const asyncHandler = require('./async-handler');
const loader = require('./ssr-stream');

// Wrap your async function, with asyncHandler
app.get('/foo', asyncHandler(async(req, res) => {
    throw new Error('Foo'); // This will go to the express error middleware
}));

app.get('/*', asyncHandler(loader(filePath, observer)));

app.use((err, req, res, next) => {

    // Handle the error type, and set the correct status code
    const status = 500;
    res
        .status(status)
        .end(err.message);
});

You should check it in your function expression, not in the function declaration. In the function itself, just throw whenever there is an error. Then, wrap it in a try/catch block :

try {
  await ssrStream(htmlFilePath, observer);
} catch(e) {
  // Handle error here
}

It's also possible to chain a catch directly after your async function (which is essentially a promise) :

await ssrStream(htmlFilePath, observer)
  .catch(e => // handle error here);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM