由於記性差因此記錄下來,看源碼更多的時候看一種思想,koa2使用了不少es6的語法,因此就以看源碼來學習語法吧。 看完koa的源碼,最核心的一塊就是洋蔥式調用。因此我就單獨吧這塊的代碼簡化下來,以便本身之後忽然想起來再看的時候不須要從新去捋思路了。node
use(fn) {
if (typeof fn !== 'function') throw new TypeError('middleware must be a function!');
if (isGeneratorFunction(fn)) {
fn = convert(fn);
//轉換爲async 函數
}
this.middleware.push(fn);
return this;
//返回新實例
}
複製代碼
app.listen(3000, () => {
})
複製代碼
listen(...args) {
const server = http.createServer(this.callback());
return server.listen(...args);
}
複製代碼
callback() {
const fn = compose(this.middleware);
if (!this.listeners('error').length) this.on('error', this.onerror);
const handleRequest = (req, res) => {
const ctx = this.createContext(req, res);
return this.handleRequest(ctx, fn);
};
return handleRequest;
}
複製代碼
function compose (middleware) {
//middleware 回調數組
return function (context, next) {
// last called middleware #
let index = -1;
return dispatch(0)
}
//返回一個prm狀態
}
複製代碼
function dispatch (i) {
if (i <= index) return Promise.reject(new Error('next() called multiple times'))
//判斷若是i小於index直接返回錯誤
index = i;
let fn = middleware[i]; //取出數組中對應下標函數
if (i === middleware.length) fn = next;
if (!fn) return Promise.resolve();
try {
return Promise.resolve(fn(context, function next () {
return dispatch(i + 1)
//遞歸調用
}))
} catch (err) {
return Promise.reject(err)
}
}
由於是async 因此當 await 接收到返回的Promise結果之後就會逐個執行下去 ,
也就是說當async函數被逐個執行完畢之後返回一個Promise對象,那麼就會從async函數最後一個await逐個向上返回調用,直到全部await執行完畢。
這就是洋蔥式調用
async function(){
await fun1(async function() {
await fun2(async function() {
await fun3(async function(){
return Promise.resolve();
});
});
});
};
上一級的await一直在等待下一級的返回結果,因此逐級向下執行,在等到執行了Promise.resolve();有了返回結果之後再逐級向上返回
//
複製代碼
handleRequest(ctx, fnMiddleware) {
return fnMiddleware(ctx).then(handleResponse).catch(onerror);
//fnMiddleware 就是遞歸執行完畢之後返回prm對象接收一個函數
}
//callback裏調永compose函數並將middleware傳遞過去
複製代碼
//最後一行其實就是返回的fn對象es6
koa的思想其實就是運用了es7的新特性async函數的新特性,逐個等待異步的結果,一旦下層的返回結果就會逐個告訴轉達給上層,就造成了洋蔥式的調用,因此要讀懂源碼必須瞭解async函數,因此在讀碼的時候也同時學習複習了async函數,仍是很不錯的。若是不懂這個函數也許會在遞歸調用那塊搞暈,會不明白遞歸調用完了之後爲何會按順序返回結果。我以爲搞懂這個就算是搞懂koa2的核心思想了,其餘的都是一些封裝函數,能夠慢慢看數組
app.use(async (ctx, next) => {
console.log(1)
//典型語法await在等待
await next();
console.log(2)
});
app.use(async (ctx, next) => {
console.log(3)
//典型語法await在等待
await next();
console.log(5)
});
返回結果 是 1,3,5,2,
這就是洋蔥
這裏附上經典的圖吧
複製代碼