>  기사  >  웹 프론트엔드  >  Express가 비동기 메소드 공유를 지원하도록 하세요

Express가 비동기 메소드 공유를 지원하도록 하세요

小云云
小云云원래의
2018-01-26 16:36:291664검색

이 글에서는 주로 Express 지원 async/await를 만드는 방법을 자세히 소개합니다. 편집자는 꽤 좋다고 생각해서 지금 공유하고 참고용으로 올려드리겠습니다. 편집자를 따라가서 모두에게 도움이 되기를 바랍니다.

Node.js v8 출시와 함께 Node.js는 기본적으로 async/await 기능을 지원했으며, 웹 프레임워크 Koa도 async/await 미들웨어를 지원하고 처리할 수 있는 새로운 기능을 제공하는 Koa 2의 공식 버전을 출시했습니다. 비동기 콜백. 매우 편리합니다.

Koa 2는 이미 async/await 미들웨어를 지원하므로 Koa를 직접 사용하고 Express를 수정하여 async/await 미들웨어를 지원하는 것은 어떨까요? Koa 2의 정식 버전이 출시된 지 얼마 되지 않았고, 여전히 많은 오래된 프로젝트에서 Express를 사용하고 있기 때문에 이를 전복하고 Koa로 다시 작성하는 것은 불가능합니다. 이 비용은 너무 높지만, Express가 가져다주는 편리함을 활용하고 싶다면. 새로운 구문을 사용하려면 Express만 변환할 수 있으며 이 변환은 비즈니스에 방해가 되지 않아야 합니다. 그렇지 않으면 많은 문제가 발생합니다.

async/await를 직접 사용

먼저 Express에서 async/await 함수를 직접 사용하는 상황을 살펴보겠습니다.

const express = require('express');
const app = express();
const { promisify } = require('util');
const { readFile } = require('fs');
const readFileAsync = promisify(readFile);
  
app.get('/', async function (req, res, next){
 const data = await readFileAsync('./package.json');
 res.send(data.toString());
});
// Error Handler
app.use(function (err, req, res, next){
 console.error('Error:', err);
 res.status(500).send('Service Error');
});
  
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

위는 Express를 수정하지 않고, async/await 함수를 직접 사용하여 http://127.0.0.1:3000/ 요청시 정상적으로 요청이 가능한 것으로 확인되며, 응답이 옵니다. 정상적으로 응답도 가능합니다. Express를 변경하지 않고도 async/await 함수를 직접 사용할 수 있는 것 같은데, async/await 함수에서 오류가 발생하면 오류 처리 미들웨어로 처리할 수 있나요? 이제 존재하지 않는 파일을 읽어 보겠습니다. 예를 들어 이전에 읽은 package.json을 age.json으로 바꿉니다.

app.get('/', async function (req, res, next){
 const data = await readFileAsync('./age.json');
 res.send(data.toString());
});

이제 http://127.0.0.1:3000/을 요청하면 요청 응답이 지연되어 결국 시간 초과된다는 것을 알게 됩니다. 터미널에서 다음 오류가 보고되었습니다.

오류 처리 미들웨어에서 오류가 처리되지 않았지만 unhandledRejection 예외가 발생한 것으로 나타났습니다. 이제 try/catch를 사용하여 수동으로 오류를 포착하면 어떻게 될까요? 오류?

app.get('/', async function (req, res, next){
 try {
  const data = await readFileAsync('./age.json');
  res.send(datas.toString());
 } catch(e) {
  next(e);
 }
});

는 요청이 오류 처리 미들웨어에 의해 처리되었음을 발견했습니다. 이는 오류를 수동으로 명시적으로 캡처하는 것은 괜찮지만 각 미들웨어나 요청 처리 기능에 try/catch를 추가하는 것은 너무 부적절하다는 것을 보여줍니다. 비즈니스 코드는 다소 거슬리고 보기에도 좋지 않습니다. 따라서 async/await 함수를 직접 사용한 실험을 통해 우리는 비즈니스 코드를 침해하지 않고 async/await 함수에서 발생하는 오류를 수신할 수 있도록 하는 것이 Express 변형의 방향이라는 것을 알게 되었습니다.

Transform Express

Express에서 라우팅 및 미들웨어를 처리하는 방법에는 두 가지가 있습니다. 하나는 Express를 통해 앱을 만들고, 미들웨어를 추가하고, 다음과 같이 앱에서 직접 라우팅을 처리하는 것입니다.

const express = require('express');
const app = express();
  
app.use(function (req, res, next){
 next();
});
app.get('/', function (req, res, next){
 res.send('hello, world');
});
app.post('/', function (req, res, next){
 res.send('hello, world');
});
  
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

다른 하나는 라우팅입니다. Express의 Router를 통해 생성된 인스턴스입니다. 다음과 같이 라우팅 인스턴스에 직접 라우팅을 추가합니다.

const express = require('express');
const app = express();
const router = new express.Router();
app.use(router);
  
router.get('/', function (req, res, next){
 res.send('hello, world');
});
router.post('/', function (req, res, next){
 res.send('hello, world');
});
  
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

이 두 가지 방법을 혼합하여 사용할 수 있습니다. 이제 앱 모양의 앱을 만드는 방법에 대해 생각해 보겠습니다. , async function(req, res, next){}) 함수를 사용하여 내부의 비동기 함수에서 발생하는 오류를 균일하게 처리할 수 있습니까? 물론 오류를 균일하게 처리하려면 next(err)를 호출하여 오류를 오류 처리 미들웨어에 전달해야 합니다. 비동기 함수는 Promise를 반환하므로 asyncFn().then( ).catch.(function(err){ next(err) })이므로 이렇게 수정하면 다음과 같은 코드가 됩니다.

app.get = function (...data){
 const params = [];
 for (let item of data) {
  if (Object.prototype.toString.call(item) !== '[object AsyncFunction]') {
   params.push(item);
   continue;
  }
  const handle = function (...data){
   const [ req, res, next ] = data;
   item(req, res, next).then(next).catch(next);
  };
  params.push(handle);
 }
 app.get(...params)
}

위 코드에서는 매개변수에 async가 있는지 확인합니다. app.get() 함수 함수는 item(req, res, next).then(next).catch(next);를 사용하여 처리되므로 함수 내에서 발생한 오류를 캡처하여 오류 처리 미들웨어에 전달할 수 있습니다. 그런데 이 코드에는 명백한 실수가 있는데, 마지막에 app.get()을 호출하는데, 이는 재귀적이어서 app.get의 기능을 파괴하고, 요청을 전혀 처리할 수 없으므로 계속해서 수정해야 합니다. .

앞서 Express의 두 가지 라우팅 처리 방식과 미들웨어가 혼합될 수 있다고 말했으므로 재귀를 피하기 위해 이 두 가지 방법을 혼합하겠습니다. 코드는 다음과 같습니다.

const express = require('express');
const app = express();
const router = new express.Router();
app.use(router);
  
app.get = function (...data){
 const params = [];
 for (let item of data) {
  if (Object.prototype.toString.call(item) !== '[object AsyncFunction]') {
   params.push(item);
   continue;
  }
  const handle = function (...data){
   const [ req, res, next ] = data;
   item(req, res, next).then(next).catch(next);
  };
  params.push(handle);
 }
 router.get(...params)
}

위와 같이 변환한 후에는 모든 것이 정상적으로 작동하는 것 같습니다. . 요청이 정상적으로 처리됩니다. 그러나 Express의 소스 코드를 살펴보면 app.get()이 라우팅을 처리할 뿐만 아니라 애플리케이션 구성도 얻을 수 있기 때문에 app.get() 메서드가 파괴된 것을 발견했습니다. Express의 해당 소스 코드는 다음과 같습니다.

methods.forEach(function(method){
 app[method] = function(path){
  if (method === 'get' && arguments.length === 1) {
   // app.get(setting)
   return this.set(path);
  }
  
  this.lazyrouter();
  
  var route = this._router.route(path);
  route[method].apply(route, slice.call(arguments, 1));
  return this;
 };
});

따라서 변환 중에 app.get에 대한 특수 처리도 수행해야 합니다. 실제 애플리케이션에서는 get 요청뿐만 아니라 게시, 넣기 및 삭제 요청도 있으므로 최종적으로 변환된 코드는 다음과 같습니다.

const { promisify } = require('util');
const { readFile } = require('fs');
const readFileAsync = promisify(readFile);
const express = require('express');
const app = express();
const router = new express.Router();
const methods = [ 'get', 'post', 'put', 'delete' ];
app.use(router);
  
for (let method of methods) {
 app[method] = function (...data){
  if (method === 'get' && data.length === 1) return app.set(data[0]);

  const params = [];
  for (let item of data) {
   if (Object.prototype.toString.call(item) !== '[object AsyncFunction]') {
    params.push(item);
    continue;
   }
   const handle = function (...data){
    const [ req, res, next ] = data;
    item(req, res, next).then(next).catch(next);
   };
   params.push(handle);
  }
  router[method](...params);
 };
}
   
app.get('/', async function (req, res, next){
 const data = await readFileAsync('./package.json');
 res.send(data.toString());
});
   
app.post('/', async function (req, res, next){
 const data = await readFileAsync('./age.json');
 res.send(data.toString());
});
  
router.use(function (err, req, res, next){
 console.error('Error:', err);
 res.status(500).send('Service Error');
}); 
   
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

이제 변환이 완료되었으므로 작은 코드 조각만 추가하면 됩니다. async를 직접 사용하세요. 이 함수는 요청을 처리하는 핸들러 역할을 하며 비즈니스에 방해가 되지 않습니다. 발생한 오류는 오류 처리 미들웨어로 전달될 수도 있습니다.

관련 권장 사항:

NodeJs의 비동기 처리 및 대기를 통한 비동기 처리 방법

Node.js에서 비동기 기능을 사용하는 방법

ES6의 async+await 동기화/비동기 솔루션에 대한 자세한 설명

위 내용은 Express가 비동기 메소드 공유를 지원하도록 하세요의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.