フロントエンドPromiseチェーン呼び出しの代わりにKoaミドルウェアに基づく


文書ディレクトリ
  • まずいくつかのキーワード
  • を理解します
  • 問題シーン
  • 実現一:流水式処理
  • 実装2:Promiseチェーンコール
  • 分割フォーム発行時に処理する各サブロジック
  • 各サブロジックを`submit`関数にまとめる

  • 実現三:挿抜可能なミドルウェアモード
  • を使用
  • 1. `koa-compose`が提供する`compose`関数を直接参照して、私たちが提供するミドルウェア
  • を組み合わせます.
  • 2. `Koa`のようなミドルウェア管理メカニズムおよびエントリ実行メカニズム
  • を提供する
  • 3. 具体的には
  • を用いる.
  • 4. 最初の質問シーン
  • と組み合わせる




    まずいくつかのキーワードを理解します
  • Koaミドルウェアとその玉ねぎリングモデル
  • koa-compose
  • よく見られる中間部品の原理浅析
  • Promiseチェーンコール
  • Promiseチェーンコール

  • 質問シーン
    大きなフォームページがあると仮定し、フォームをコミットする前に以下のことをする必要があります.
  • フォームフィールドチェック(メールボックスフォーマットチェックなど)
  • 個別フィールドの機密語チェック
  • フィールド名またはフィールド値フォーマット処理(時間フォーマットなど)
  • をコミットする.
  • バックエンド
  • にデータをコミットする.
    以下,それぞれ3つの異なる実装方式を分析する.
    実現一:流水式処理
    //         4      
    const submit = () => {
         
      /**
       * 1.     
       *                
       */
      if (!formValid) {
         
        return false;
      }
    
      /**
       * 2.      
       *               
       */
      if (!sensitiveValid) {
         
        return false;
      }
    
      /**
       * 3.          
       *                 
       */
      formFields.format();
    
      /**
       * 4.     
       *              
       */
      formFields.submit();
    };
    
    submit関数は4つの異なる処理ロジックを含み、これにより他の処理ロジックを記入することが困難になり、後期メンテナンスコストが高く、同時に開閉原則に違反する.
    実装2:Promiseチェーン呼び出し
    フォームの発行時に処理するサブロジックの分割
    let formValidPromise = new Promise((resolve, reject) => {
         
      /**
       * 1.     
       *                
       */
      if (formValid) {
         
        resolve(true);
      } else {
         
        resolve(false);
      }
    });
    
    let sensitiveValidPromise = new Promise((resolve, reject) => {
         
      /**
       * 2.      
       *               
       */
      if (sensitiveValid) {
         
        resolve(true);
      } else {
         
        resolve(false);
      }
    });
    
    let formFormatPromise = new Promise((resolve, reject) => {
         
      /**
       * 3.          
       *                 
       */
      resolve(true);
    });
    
    let formSubmitPromise = new Promise((resolve, reject) => {
         
      /**
       * 4.     
       *              
       */
      formFields.submit();
      resolve(true);
    });
    

    各サブロジックをsubmit関数にまとめる
    const submit = () => {
         
      //     
      formValidPromise().then((isValid) => {
         
        if (isValid) {
         
          return formValidPromise();
        }
        return reject({
         
          formValid: false
        });
      }).then((sensitiveValid)  => {
         
        if (sensitiveValid) {
         
          return sensitiveValidPromise();
        }
        return reject({
         
          sensitiveValid: false
        });
      }).then(() => {
         
        return formFormatPromise();
      }).then(() => {
         
        return formSubmitPromise();
      }).catch(error => {
         
        console.log('error: ', error);
      });
    };
    
    const submit = async () => {
         
      //    async/await      
      try {
         
        await formValidPromise();
        await sensitiveValidPromise();
        await formFormatPromise();
        await formSubmitPromise();
      } catch(error) {
         
        //    reject   
        console.log('error: ', error);
      }
    };
    
  • 各サブプロセッシングロジックを抽出して後期にメンテナンスし、submit関数に対する汚染を低減する
  • .
  • Promiseチェーン呼び出しにより、コミットプロセス全体がより制御可能になる
  • 同時に以下の問題を引き起こす.
  • 新しいサブプロセッシングロジックを追加するにはsubmit関数
  • を修正する必要がある.
  • サブプロセッシングロジックの順序を調整するには、submit関数
  • を修正する必要がある.
    実現三:挿抜可能なミドルウェアモードを使用する
    1.koa-composeによって提供されたcompose関数を直接参照し、我々が提供したミドルウェアを組み合わせる
    /**
     * Compose `middleware` returning
     * a fully valid middleware comprised
     * of all those which are passed.
     *
     * @param {Array} middleware
     * @return {Function}
     * @api public
     */
    
    function compose (middleware) {
         
      if (!Array.isArray(middleware)) throw new TypeError('Middleware stack must be an array!')
      for (const fn of middleware) {
         
        if (typeof fn !== 'function') throw new TypeError('Middleware must be composed of functions!')
      }
    
      /**
       * @param {Object} context
       * @return {Promise}
       * @api public
       */
    
      return function (context, next) {
         
        // last called middleware #
        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)
          }
        }
      }
    }
    

    2.Koaのようなミドルウェア管理機構及び入口実行機構を提供する
    //    
    class Middleware {
         
      constructor () {
         
        this.middleare = [];
      }
    
      use(fn) {
         
        if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
        this.middleware.push(fn);
        return this;
      }
    
      init() {
         
        //           
        const fn = compose(this.middleware);
    
        const dispatch = () => {
         
          //            
          const ctx = Object.create(null);
          return this.dispatch(ctx, fn)
        }
    
        return dispatch;
      }
    
      dispatch(ctx, fnMiddleware) {
         
        return fnMiddleware(ctx).then(() => {
         
          //                 
          console.log('ctx: ', ctx);
        }).catch((error) => {
         
          console.log(error);
        });
      }
    }
    
    export default Middleware;
    

    3.具体的な使用
    let middleware = new Middleware();
    
    middleare.use(async (ctx, next) => {
         
      console.log('ctx1: ', ctx);
      await next();
    });
    
    middleare.use(async (ctx, next) => {
         
      console.log('ctx2: ', ctx);
      await next();
    });
    
    let dispatch = middleware.init();
    
    dispatch() //        
    

    4.最初の質問シーンに合わせる
    let formValidMd = async (ctx, next) => {
         
      /**
       * 1.        
       *                
       */
      if (formValid) {
         
        ctx.formValid = true;
        await next();
      } else {
         
        ctx.formValid = false;
      }
    };
    
    let sensitiveValidMd = async (ctx, next) => {
         
      /**
       * 2.         
       *               
       */
      if (sensitiveValid) {
         
        ctx.sensitiveValid = true;
        await next();
      } else {
         
        ctx.sensitiveValid = false;
      }
    };
    
    let formFormatMd = async (ctx, next) => {
         
      /**
       * 3.             
       *                 
       */
      ctx.formFormat = true;
      await next();
    };
    
    let formSubmitMd = async (ctx, next) => {
         
      /**
       * 4.        
       *              
       */
      formFields.submit();
      ctx.formSubmit = true;
      await next();
    };
    
    //      ,      use      
    let middleware = new Middleware();
    middleare.use(formValidMd);
    middleare.use(sensitiveValidMd);
    middleare.use(formFormatMd);
    middleare.use(formSubmitMd);
    
    let dispatchSubmit = middleare.init();
    
    
    submitの関数実装を見てみましょう
    const submit = () => {
         
      dispatchSubmit();
    }
    

    これまでのsubmit関数ではコードが少なくなりました で解決すべき問題を振り返ってみましょう
  • 新しいサブプロセッシングロジックを追加するにはsubmitの関数を修正する必要があります->サブロジックプロセッシングミドルウェアを追加するだけで、use
  • 件の問題を解決します.
  • サブプロセッシングロジックの順序を調整するにはsubmitの関数を修正する必要がある->現在順序を変更するには、ミドルウェアuseの前後関係
  • を調整する必要がある.
    サブ処理ロジックはsubmit関数と完全にデカップリングされ,開放閉鎖設計の原則に合致した.書くコードはもとは多くなりましたが、メンテナンスコストもずいぶん下がって、具体的に需要のあるシーンを取捨選択して、具体的に分析して、具体的に解決します.