slackkoala 2019-06-27
async await
的特点,形成了一个洋葱式的流程,和 JS 的事件流 (捕获 -> target -> 冒泡) 相似handleRequest(ctx, fnMiddleware) { const res = ctx.res; res.statusCode = 404; const onerror = err => ctx.onerror(err); const handleResponse = () => respond(ctx); onFinished(res, onerror); return fnMiddleware(ctx).then(handleResponse).catch(onerror); }上述代码是 request 事件的句柄,也就是说每一个请求到来,都会执行这个总方法
res.end(body)
fnMiddleware(ctx)
就是执行所有中间件函数,然后返回一个 Promise 对象,不出错的话执行 handleResponse
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 // 返回给 next() if (!fn) return Promise.resolve() try { // 返回给 next(),最外一层返回给 fnMiddleware(ctx).then(handleResponse) return Promise.resolve(fn(context, function next () { // 返回给外一层 fn 的 await return dispatch(i + 1) })) } catch (err) { return Promise.reject(err) } } }
fnMiddleware(ctx).then(handleResponse)
)index
,是记录执行过的中间件数量。一旦有序号大于数量,说明有中间件执行了两次 await next
,这是不被允许的function dispatch(0){ // 第一层的序号 return Promise.resolve(async function a0(){ cnosole.log('0-0') await 111(function next0(){ return (function dispatch(1){ // 第二层的序号 return Promise.resolve(async function a1(){ cnosole.log('1-0') await 222(function next1(){ return (function dispatch(2){ // 第三层的序号 return Promise.resolve(async function a2(){ cnosole.log('2-0') await 333(function next2(){ return (function dispatch(3){ // i == middleware.length ,算是洋葱芯吧 // fn[3] == undefined,说明中间件已经到洋葱的最里面了,开始向外返回 return Promise.resolve() })() })()333 console.log('2-1') }) })() })()222 console.log('1-1') }) })() })()111 console.log('0-1') }) } dispatch(0).then(handleResponse)
app.use(async function (ctx,next) { console.log('1-1') await new Promise(function(resolve, reject){ setTimeout(function () { console.info ("wait for 10 mini seconds."); resolve(); },10); }); console.log('1-2') next(); console.log('1-3') }) app.use(async function (ctx,next) { console.log('2-1') await new Promise(function(resolve){ setTimeout(function () { console.info ("wait for 10 mini seconds"); resolve(); },10); }); console.log('2-2') next(); console.log('2-3') })试试 next() 前面加上 await 和不加 await 的区别就明白了
res、req
对象的封装。其他的功能都由外部中间件提供。代码不是很多,但是很精妙,对于代码能力的提高有不小的帮助