KKA玉ねぎモデルを理解する
8383 ワード
中間部品の特性コンテキストctx await next()制御前後置動作 の後付け操作はデータの解凍-スタックと似ています.高度後 を出します.
promiseのシミュレーションは next()を使わない場合、awaitの実行順序は何ですか?この例では、 であるからです.前置動作が非同期の操作である場合?
Promiseの入れ子はミドルウェアの流れを実現することができますが、入れ子のコードはメンテナンス性と可読性の問題を発生し、中間部品の拡張にも問題があります.Kooa.jsのミドルエンジンは、コa-composeモジュールで実現され、つまりKooa.jsがタマネギモデルのコアエンジンを実現します.coa-compose
| |
| middleware 1 |
| |
| +-----------------------------------------------------------+ |
| | | |
| | middleware 2 | |
| | | |
| | +---------------------------------+ | |
| | | | | |
| action | action | middleware 3 | action | action |
| 001 | 002 | | 005 | 006 |
| | | action action | | |
| | | 003 004 | | |
| | | | | |
+-------------------------------------------------------------------------------------- | | | | | |
| | | | | |
| | +---------------------------------+ | |
| +-----------------------------------------------------------+ |
+----------------------------------------------------------------------------------+
はまず全文を貫くkoaのコードconst Koa = require('koa');
let app = new Koa();
const middleware1 = async (ctx, next) => {
console.log(1);
await next();
console.log(6);
}
const middleware2 = async (ctx, next) => {
console.log(2);
await next();
console.log(5);
}
const middleware3 = async (ctx, next) => {
console.log(3);
await next();
console.log(4);
}
app.use(middleware1);
app.use(middleware2);
app.use(middleware3);
app.use(async(ctx, next) => {
ctx.body = 'hello world'
})
app.listen(3001)
// 1,2,3,4,5,6
await next()
を書いて、各middlewareを分けて、前置操作して、他の中間部品の操作を待って、中間部品の特性を観察することができる:promiseのシミュレーションは
Promise.resolve(middleware1(context, async() => {
return Promise.resolve(middleware2(context, async() => {
return Promise.resolve(middleware3(context, async() => {
return Promise.resolve();
}));
}));
}))
.then(() => {
console.log('end');
});
このアナログコードからnext()が戻ってくるのがpromiseであることが分かります.awaitを使ってpromiseのresove値を待つ必要があります.プロミセの入れ子はタマネギの模型のような形をしています.awaitが一番奥の階のpromiseのresoveの値まで1階に包んでいます.思考:next()
だけの実行順序がawait next()
と同じであれば、nextの前置き動作は同期const p = function(args) {
return new Promise(resolve => {
setTimeout(() => {
console.log(args);
resolve();
}, 100);
});
};
const middleware1 = async (ctx, next) => {
await p(1);
// await next();
next();
console.log(6);
};
const middleware2 = async (ctx, next) => {
await p(2);
// await next();
next();
console.log(5);
};
const middleware3 = async (ctx, next) => {
await p(3);
// await next();
next();
console.log(4);
};
// :1,6,2,5,3,4
プログラムがmiddleware 1に実行され、await p(1)
までpromise値が飛び出すのを待って次のイベントサイクルに戻ると、next()、つまりmiddleware 2に実行され、またawait p(2)
まで実行し、promiddleware 2から飛び出すのを待って、middleware 1に戻って引き続きconsolie.logs(6)を実行し、これは類推1.656.24で出力します.Promiseの入れ子はミドルウェアの流れを実現することができますが、入れ子のコードはメンテナンス性と可読性の問題を発生し、中間部品の拡張にも問題があります.Kooa.jsのミドルエンジンは、コa-composeモジュールで実現され、つまりKooa.jsがタマネギモデルのコアエンジンを実現します.coa-compose
this.middleware = [];
use(fn) {
this.middleware.push(fn);
……
}
callback() {
const fn = compose(this.middleware);
……
}
function compose (middleware) {
return function (context, next) {
let index = -1
return dispatch(0)
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
index = i
let fn = middleware[i]
if (i === middleware.length) fn = next
if (!fn) return Promise.resolve()
try {
return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
} catch (err) {
return Promise.reject(err)
}
}
}
}
Kooa実装のコードは非常にシンプルであり、useを使用してmiddlewareを配列の中に存在させ、要求をブロックしたらcalback方法を実行し、calbackでcomposeを呼び出し、compose方法は再帰的に中間部品を実行し、promise.resolve()
に戻る.実際に最後に実行されるコードも上記のプロミセ入れ子の形です.拡張:AwaitとGeneratorは通常私達の都会はawaitがふさがって後の操作がpromiseのresoveの戻り値あるいはその他の値を待つと言って、もしawaitこの文法のあめがないならば、どのように実現しますか?この待ち時間はどうやってコントロールしますか?Generator Generatorは、実際には特殊なシフタlet gen = null;
function* genDemo(){
console.log(1)
yield setTimeout(()=>{
console.log(3);
gen.next();// c
},100)
console.log(4)
}
gen = genDemo();// a
gen.next(); // b
aです.generatorを呼び出します.この関数は実行されません.つまり、まだ出力されていません.内部状態を指すエルゴードオブジェクトを返します.b.generator関数が実行を開始し、出力1は、最初のyeild表現が停止し、gen.next()を呼び出してオブジェクトの「value:10、done:false」を返します.ここのvalueはset Timeoutの識別値、つまりclearTimeoutのパラメータを呼び出して、数字です.ドーンは遍歴がまだ終わっていないと表しています.100ミリ秒後に3を出力します.c.Generator関数は、前回yeildで停止したところから関数終了(他のyeildがない)まで実行され、出力4は、「value:undefined,done:true」に戻り、エルゴード終了を表します.yeildには制御コードの進捗が見られますが、awaitとは異なる働きがあるかどうかは、awaitがgenerator形式のコードにコンパイルされています.いくつかのコードが多くなりましたが、_asyncToGenerator(function*() {……}
をgeneratorと呼びます.asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
をgen.nextと見なします.分かりやすくなりました.function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function() {
var self = this,
args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
const middleware1 =
/*#__PURE__*/
(function() {
var _ref = _asyncToGenerator(function*(ctx, next) {
console.log(1);
yield next();
console.log(6);
});
return function middleware1(_x, _x2) {
return _ref.apply(this, arguments);
};
})();
const middleware2 =
/*#__PURE__*/
(function() {
var _ref2 = _asyncToGenerator(function*(ctx, next) {
console.log(2);
yield next();
console.log(5);
});
return function middleware2(_x3, _x4) {
return _ref2.apply(this, arguments);
};
})();
const middleware3 =
/*#__PURE__*/
(function() {
var _ref3 = _asyncToGenerator(function*(ctx, next) {
console.log(3);
yield next();
console.log(4);
});
return function middleware3(_x5, _x6) {
return _ref3.apply(this, arguments);
};
})();
Promise.resolve(
middleware1(
context,
/*#__PURE__*/
_asyncToGenerator(function*() {
return Promise.resolve(
middleware2(
context,
/*#__PURE__*/
_asyncToGenerator(function*() {
return Promise.resolve(
middleware3(
context,
/*#__PURE__*/
_asyncToGenerator(function*() {
return Promise.resolve();
})
)
);
})
)
);
})
)
).then(() => {
console.log("end");
});
はリンクを参照する:https://chenshenhai.github.io...https://segmentfault.com/a/11...