この記事では、Express の async/await をサポートする方法を主に詳しく紹介します。編集者が非常に優れていると考えたので、参考として共有します。編集者をフォローして見てみましょう。皆さんのお役に立てれば幸いです。
Node.js v8 のリリースにより、Node.js は async/await 関数をネイティブにサポートするようになり、Web フレームワーク Koa も Koa 2 の正式バージョンをリリースしました。これは、async/await ミドルウェアをサポートし、処理する新しい機能をもたらします。非同期コールバックは非常に便利です。
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の変革の方向性であることが分かりました。
Express の変換
Express でルーティングとミドルウェアを処理するには 2 つの方法があります。1 つは、次のように Express でミドルウェアを追加し、アプリ上で直接ルーティングを処理する方法です。 Express の Router を通じてインスタンスを作成します。次のように、ルーティング インスタンス上でミドルウェアを追加し、ルーティングを処理します。
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 }/`); });
次に、アプリ型のアプリを作成する方法を考えてみましょう。 、async function(req, res, next){}) 関数を使用すると、内部の非同期関数によってスローされたエラーを均一に処理できるようになりますか?もちろん、エラーを均一に処理するには、next(err) を呼び出してエラーをエラー処理ミドルウェアに渡す必要があります。async 関数は Promise を返すため、asyncFn().then( の形式にする必要があります。 ).catch. (function(err){ next(err) }) なので、次のように変更すると、次のコードになります:
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 があるかどうかを判断します。 app.get() 関数 関数は item(req, res, next).then(next).catch(next); を使用して処理されるため、関数内でスローされたエラーをキャプチャしてエラー処理ミドルウェアに渡すことができます。ただし、このコードには明らかな間違いがあります。最後に app.get() を呼び出します。これは再帰的で、app.get の関数を破壊し、リクエストをまったく処理できません。そのため、引き続き修正する必要があります。 。
Express のルーティングとミドルウェアを処理する 2 つの方法は混合できると述べました。そのため、再帰を避けるためにこれら 2 つの方法を混合します。 コードは次のとおりです。
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) }
上記のような変換後、すべてが正常に動作しているように見えます。リクエストは正常に処理されます。ただし、Express のソース コードを確認すると、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) }
したがって、変換中に、app.get に対して特別な処理を行う必要もあります。実際のアプリケーションでは、get リクエストだけでなく、post、put、delete リクエストもあるので、最終的に変換したコードは次のようになります:
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; }; });
これで変換は完了しました。小さなコードを追加するだけです。 async を直接使用する この関数はリクエストを処理するハンドラーとして機能し、ビジネスに影響を与えません。スローされたエラーは、エラー処理ミドルウェアに渡すこともできます。
関連する推奨事項:
以上がExpress で非同期メソッド共有をサポートするの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。