Maple's Blog.

Koa-Compose 源码试写

字数统计: 459阅读时长: 2 min
2019/12/16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
async function _compose(ctx, next, items) {
if(items.length === 0) {
return next();
}

const func = items.shift();
return func(ctx, async function() {
return _compose(ctx, next, items);
});
}

function compose(items) {
return async function(ctx, next) {
return _compose(ctx, next, items);
}
}

const items = [
function(ctx, next) {
console.log('a.start');
next();
console.log('a.end');
},

function(ctx, next) {
console.log('b.start');
next();
console.log('b.end');
},

function(ctx, next) {
console.log('c.start');
next();
console.log('c.end');
},
]

compose(items)({}, function() { console.log('end') });

注意几点是,如果有函数 func 就必须以 await func() 的方式来运行,这样保证 func 无论是普通函数或者 promise 函数,都可以正常运行。同样的还有 await next() 函数


发现比较有趣的一点,如果是 async 函数,最后的结果是 return await main(),那就会和 return main() 结果一致。当然实际运行的过程却是不一样的。

1
2
3
async main() => {
return await done();
}

相当于在main() 的生命周期内,先执行 done(),然后把返回值返回。因为是在 async 函数中,返回时会重新用 Promise 封装一层。最后返回一个 Promise 对象。

1
2
3
async main() => {
return done();
}

就完全不一样,在main() 的生命周期中, done() 只是返回一个 promise 对象,并同步开始执行(前者是已经执行完毕)。即使到最后 async 封装一层 Promise 之后,函数其实也并未执行完成。而是等待下一个 await 方法来返回对象。

虽然后者的功能一致并且可以省略一个语法词,但是推荐还是用前者的办法来编写。因为前者在修改变量也丝毫不影响,但是后者因为是 promise 对象不能直接修改。

1
2
3
4
5
6
7
8
9
async main() => {
const a = await done();
return a + 1;
}

async main() => {
const a = done();
return a + 1; // error
}
CATALOG