まえがき
私は長い間、Web開発の単一言語としてjavascriptに魅了されてきましたが、最近まで、私の研究はすべて、nodejsのドキュメントと、これがコールバック地獄であるという記事を読むことで終わりました。 yieldステートメントが調和して現れたことが判明するまで、コアに出会ってから出かけます。
塩は何ですか
実際、koaは、ユビキタスコールバックを除いて、多くの点でその前身であるexpressに似ています。 代わりに、コルーチンを使用して、サブプログラム(サンク)、プロミス(プロミス)、サブプログラム/プロミスの配列、またはオブジェクトに制御を移動できます。 一部の場所では、koa作成者と多くのフォロワーによって作成された共同関数のグループを通じて、下位互換性も保持されています。 コールバックを使用するために使用される関数は、coまたはkoaで使用するためにサンク化できます。
次のようになります。
var func = function(opt){ return function(done){ /* … */ (…) && done(null, data) || done(err) } } var func2 = function(opt){ return function(done){ oldFuncWithCallback(opt, function(err, data){ (...) && done(null, data) || done(err) } } } co(function*{ /* … */ var result = yield func(opt); var result2 = yield func2(opt); var thunkify = require('thunkify'); var result3 = yield thunkify(oldFuncWithCallback(opt)) })()
同時に、データは結果に戻り、done(err)は例外をスローし、コールバックの場合のように関数を終了しません。インタープリターはブロックせず、実行は次のyieldに進みます。 -ただのおとぎ話。
コードを書く時間
Koaは、Expressと同様にミドルウェアに基づいていますが、現在はPythonのトルネードのようなコルーチンとして実行されます。 次は、シンプルなサイトのコードと私の考えです。
プロジェクト構造:
- node_modules
- src-ソースコード全体はこちら
- サーバー-サーバー
- app-アプリケーションフォルダー
- public-統計
- テンプレート-テンプレート
- config-構成ファイル
私の以前の趣味はDjangoだったので、これがプロジェクトのコードの構成に影響を与えたように思えるかもしれません。たぶんそれは本当です。コードをモジュールに整理するのが好きです。
src / server / index.js
'use strict'; var koa = require('koa'); var path = require('path'); var compose = require('koa-compose'); // middleware` var app = module.exports = koa(); // var projectRoot = __dirname; var staticRoot = path.join(projectRoot, '../public'); var templateRoot = path.join(projectRoot, '../template'); // settings.py django var middlewareStack = [ require('koa-session')(), // session require('koa-less')('/less', {dest: '/css', pathRoot: staticRoot}), // less css, , require('koa-logger')(), // http require('koa-favicon')(staticRoot + '/favicon.png'), require('koa-static')(staticRoot), // , , nginx` require('koa-views')(templateRoot, {'default': 'jade'}) // Jade nodejs ]; require('koa-locals')(app); // locals , , app.use(compose(middlewareStack)); /* middleware , - , callback` , , , */ var routes = require('./handlers'); app.use(function *(next) { // this, middleware app, this.locals.url = function (url, params) { return routes.url(url, params); }; yield next }); /* middleware, url, , , */ app.use(routes.middleware());
このチェーンは、サーバーがリクエストを受信するたびに呼び出されることに注意してください。 実行順序をよりよく理解するには、次の例を使用できます。
app.use(function*(next){ console.log(1) yield heavyFunc() console.log(2) yield next }) app.use(function*(next){ console.log(3) yield next })
コンソールへの各リクエストが表示されます
1 3 2
次に、サーバーフォルダーに、src / appフォルダーからアプリケーションを登録するモジュールであるhandlers.jsを配置します。
src / server / handlers.js
var Router = require('koa-router'); var router = new Router(); function loadRoutes(obj, routes){ routes.forEach(function(val){ var func = val.method.toLowerCase() == 'get' ? obj.get : val.method.toLowerCase() == 'post' ? obj.post : val.method.toLowerCase() == 'all' ? obj.all : obj.get; return func.call(obj, val.name, val.url, val.middleware) }) } loadRoutes(router, require('src/app/home').routes); // app module.exports = router;
モジュールはloadRoutesメソッドをカプセル化します。このメソッドは、新しく作成されたルーターインスタンスと、ルート情報を含むオブジェクトのリストを受け入れます。 ホームの例を使用して、このモジュールを操作するためのアプリケーションがどのように見えるかを示します。
src / app / home.js
function* index(next){ yield this.render('home/index', { Hello: 'World!' }) } var routes = [ {method: 'get', name: 'index', url: '/', middleware: index} ]; exports.routes = routes;
非常にシンプルでオーガニックに見えます。ここでは、djangoで提案されているモジュール方式よりも少し進んで、独自のルートを含むアプリケーションの他の部分からモジュールを完全に分離するのが好きでした。 もちろん、このアプローチでは、URLの競合が発生する可能性があり、予期したものとは異なります。 アプリケーションの名前を追加するか、koa-mountを使用するか、レジストラーを改善して重複を防ぎます。
ページをレンダリングするには、this.bodyに入力する必要があります。this.renderはこれを実行するか、次にyieldを使用して実行を転送する必要があります。そうしないと、ページの本文に「Not Found」が表示されます。 ミドルウェアのいずれも本体を埋めて実行を継続していない場合、次のミドルウェアをsrc / server / index.jsの最後に配置することにより、正しい404ページをレンダリングできます。
app.use(function*(){ this.status = 404; yield this.render('service/404') // , })
おわりに
デザートについては、エラー処理を残すことにしました。 nodejsの支持者から聞いたところ、これはすべてのコールバックにあまり注意を払う必要はなく、それでも常に助けになるとは限らないことを表明します。 ミドルウェアの実行順序を思い出すと、リクエスト処理の最初に次のコードを追加するだけでグローバル処理を実行できます。
app.use(function* (next){ try { yield next } catch (err) { this.app.emit('error', err, this); // yield this.render('service/error', { message: err.message, error: err }) } )
これにより、すべてのプロジェクトコードをtry..catchで囲みます。アプリが主にeventEmitterであることを忘れないでください。 私の意見では、これは単に素晴らしいです。 非常に多くのモジュールがすでにコア用に作成されており、ほとんどすべてのエクスプレスモジュールはすでにマングース、パスポート、リクエストなどのコアに適合しています。 そこで、喜びとファンをもたらす非同期プログラミングを手に入れました。 さらに、悪名高いTJはコアをサポートするために残っています。
哲学的には、Koaはnodejsを修正および置換しようとしていますが、Expressはnodejsを拡張しています。
記事の冒頭からの抜粋、 koa-vs-express 。
読んでくれてありがとう。 すべてのnodejsに最適です。