日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > php >内容正文

php

洋葱模型php,理解Koa洋葱模型

發布時間:2023/12/15 php 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 洋葱模型php,理解Koa洋葱模型 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

中間件特性

| |

| 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的resolve值。promise的嵌套就像是洋蔥模型的形狀就是一層包裹著一層,直到await到最里面一層的promise的resolve值返回。

思考:

如果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

當程序執行到middleware1,執行到await p(1)等待promise值返回跳出然后到下一個事件循環時,執行next()也就是執行到middleware2,再執行到await p(2)等待promise值返回跳出middleware2,回到middleware1繼續執行console.log(6),以此類推輸出順序為1.6.2.5.3.4

Promise的嵌套雖然可以實現中間件流程,但是嵌套的代碼會產生可維護性和可讀性的問題,也帶來中間件擴展的問題。

Koa.js中間件引擎是有koa-compose模塊來實現的,也就是Koa.js實現洋蔥模型的核心引擎。

koa-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)

}

}

}

}

Koa實現的代碼非常簡潔,我們在使用use的時候將middleware存在一個數組里面,當攔截到請求時執行callback方法,callback中調用了compose,compose方法使用遞歸執行中間件,遍歷完成返回promise.resolve(),實際最后執行的代碼也是上面所講的promise嵌套的形式。

擴展:Await與Generator

通常我們的都會說await阻塞后面的操作等待promise的resolve返回值或者其他值,如果沒有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,該函數不執行,也就是還沒有輸出1,返回的是指向內部狀態的遍歷對象。

b. generator函數開始執行,輸出1,遇到第一個yeild表達式停下來,調用gen.next()返回一個對象{value: 10, done:false},這里的value表示setTimeout的一個標識值,也就是調用clearTimeout的參數,是一個數字。done表示遍歷還沒有結束。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");

});

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的洋葱模型php,理解Koa洋葱模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。