KKA玉ねぎモデルを理解する

8383 ワード

中間部品の特性
    |                                                                                  |
    |                              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を分けて、前置操作して、他の中間部品の操作を待って、中間部品の特性を観察することができる:
  • コンテキストctx
  • await next()制御前後置動作
  • の後付け操作はデータの解凍-スタックと似ています.高度後
  • を出します.
    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()だけの実行順序が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...