<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] # 中間件執行順序 koa的next()方法,與express不一樣,調用后并非直接跳過當前中間件,而是該函數暫停并將控制傳遞給定義的下一個中間件。當在下游沒有更多的中間件執行后,堆棧將展開并且每個中間件恢復執行其上游行為。 ~~~ const koa = require('koa'); const app = new koa(); app.use((ctx, next) => { console.log('第一個中間件函數') next(); console.log('第一個中間件函數next之后'); }) app.use(async (ctx, next) => { console.log('第二個中間件函數') next(); console.log('第二個中間件函數next之后'); }) app.use(ctx => { console.log('響應'); ctx.body = 'hello' }) app.listen(3000) ~~~ 結果 ``` // 第一個中間件函數 // 第二個中間件函數 // 響應 // 第二個中間件函數next之后 // 第一個中間件函數next之后 ``` 使用洋蔥模型來說明 ![](https://box.kancloud.cn/124ca99aceddded2be3c2f2ca4a87b8b_800x311.png) # 使用中間件 * app.use()方法,用來將中間件添加到隊列中 * 中間件就是傳給app.use()作為的參數的函數 * 使用app.use()將函數添加至隊列之中后,當有請求時,會依次觸發隊列中的函數,也就是依次執行一個個中間件函數,執行順序按照調用app.use()添加的順序。 * 在每個中間件函數中,會執行next()函數,意思是把控制權交到下一個中間件(實際上是調用next函數后,會調用下一個中間件函數,后面解析源碼會有說明),如果不調用next()函數,不能調用下一個中間件函數,那么隊列執行也就終止了,在上面的代碼中表現就是不能響應客戶端的請求了。 ``` // koa/lib/application.js { /** * * @param {Function} fn * @return {Application} self */ use(fn) { if (typeof fn !== 'function') throw new TypeError('middleware must be a function!'); if (isGeneratorFunction(fn)) { fn = convert(fn); } debug('use %s', fn._name || fn.name || '-'); this.middleware.push(fn); return this; } } ``` <br> # 內部過程 * 內部利用 `app.use()` 添加到一個數組隊列中: ~~~ // app.use()函數內部添加 this.middleware.push(fn); // 最終this.middleware為: this.middleware = [fn,fn,fn...] ~~~ * 使用`koa-compose`模塊的`compose`方法,把這個中間件數組合并成一個大的中間件函數 ~~~ const?fn = compose(this.middleware); ~~~ * 在有請求后后會執行這個中間件函數 fn,進而會把所有的中間件函數依次執行 # koa-compose 源碼 ``` 'use strict' module.exports = compose /** * @param {Array} middleware * @return {Function} */ // compose函數需要傳入一個數組隊列 [fn,fn,fn,fn] 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 */ // compose函數調用后,返回的是以下這個匿名函數 // 匿名函數接收兩個參數,第一個隨便傳入,根據使用場景決定 // 第一次調用時候第二個參數next實際上是一個undefined,因為初次調用并不需要傳入next參數 // 這個匿名函數返回一個promise return function (context, next) { // last called middleware # //初始下標為-1 let index = -1 return dispatch(0) function dispatch (i) { // 如果傳入i為負數且<=-1 返回一個Promise.reject攜帶著錯誤信息 // 所以執行兩次next會報出這個錯誤。將狀態rejected,就是確保在一個中間件中next只調用一次 if (i <= index) return Promise.reject(new Error('next() called multiple times')) // 執行一遍next之后,這個index值將改變 index = i // 根據下標取出一個中間件函數 let fn = middleware[i] // next在這個內部中是一個局部變量,值為undefined // 當i已經是數組的length了,說明中間件函數都執行結束,執行結束后把fn設置為undefined // 問題:本來middleware[i]如果i為length的話取到的值已經是undefined了,為什么要重新給fn設置為undefined呢? if (i === middleware.length) fn = next //如果中間件遍歷到最后了。那么。此時return Promise.resolve()返回一個成功狀態的promise // 方面之后做調用then if (!fn) return Promise.resolve() // try catch保證錯誤在Promise的情況下能夠正常被捕獲。 // 調用后依然返回一個成功的狀態的Promise對象 // 用Promise包裹中間件,方便await調用 // 調用中間件函數,傳入context(根據場景不同可以傳入不同的值,在KOa傳入的是ctx) // 第二個參數是一個next函數,可在中間件函數中調用這個函數 // 調用next函數后,遞歸調用dispatch函數,目的是執行下一個中間件函數 // next函數在中間件函數調用后返回的是一個promise對象 // 讀到這里不得不佩服作者的高明之處。 try { return Promise.resolve(fn(context, function next () { return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } } } ``` 補充說明: * 根據以上的源碼分析得到,在一個中間件函數中不能調用兩次**next()**,否則會拋出錯誤 ~~~ function one(ctx,next){ console.log('第一個'); next(); next(); } ~~~ 拋出錯誤: ``` next() called multiple times ``` * `next()`調用后返回的是一個Promise對象,可以調用then函數 * 中間件函數可以是async/await函數,在函數內部可以寫任意的異步處理,處理得到結果后再進行下一個中間件函數。 ~~~ function two(ctx,next){ console.log('第二個'); next().then(function(){ console.log('第二個調用then后') }); } ~~~ <br> <br> # 測試 ``` var index = -1; function compose() { return dispatch(0) } function dispatch(i) { if (i <= index) return Promise.reject(new Error('next() called multiple times')) index = i var fn = middleware[i] if (i === middleware.length) fn = next if (!fn) return Promise.resolve('fn is undefined') try { return Promise.resolve(fn(context, dispatch.bind(null, i + 1))); } catch (err) { return Promise.reject(err) } } function f1(context, next) { console.log('middleware 1'); next().then(data => console.log(data, 'f1 then')); console.log('middleware 1'); return 'middleware 1 return'; } function f2(context, next) { console.log('middleware 2'); next().then(data => console.log(data, 'f2 then')); console.log('middleware 2'); return 'middleware 2 return'; } function f3(context, next) { console.log('middleware 3'); next().then(data => console.log(data, 'f3 then')); console.log('middleware 3'); return 'middleware 3 return'; } var middleware = [ f1, f2, f3 ] var context = {}; var next = function (context, next) { console.log('middleware 4'); next().then(data => console.log(data, 'next then')); console.log('middleware 4'); return 'middleware 4 return'; }; compose().then(data => console.log(data, 'compose then')); ``` <br> <br> 結果 ``` middleware 1 middleware 2 middleware 3 middleware 4 middleware 4 middleware 3 middleware 2 middleware 1 fn is undefined next then middleware 4 return f3 then middleware 3 return f2 then middleware 2 return f1 then middleware 1 return compose then ``` <br> # 參考資料 * [傻瓜式解讀koa中間件處理模塊koa-compose](https://segmentfault.com/a/1190000016843275) * [中間件執行模塊koa-Compose源碼分析](https://segmentfault.com/a/1190000013447551)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看