이 글에서는 주로 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의 비동기 처리 및 대기를 통한 비동기 처리 방법
ES6의 async+await 동기화/비동기 솔루션에 대한 자세한 설명
위 내용은 Express가 비동기 메소드 공유를 지원하도록 하세요의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!