nodejs + es6 看起来很美, 真拿它做点事情能把你逼疯!

Altitude-avatar

Altitude

2020-08-26T07:53:52+00:00

首先来看这段代码, 你认为输出是什么?

console.log('out 1');

new Promise((resolve) => {
setTimeout(resolve, 500);
}).then(() => {
console.log('inner');
});

console.log('out 2');

输出是:
out 1
out 2
inner

如果你想得到的是下面这个输出,那就是个非常复杂的问题.
out 1
inner
out 2

首先我理解nodejs中的回调函数性能非常好, 在做前端开发的时候特别合适. 因为前端代码中就是经常等待各种资源, 不过在nodejs, 做后端处理的时候, 这种回调函数很容易引发执行顺序的问题.

比如, 你需要提供一个对外开发的函数, 你需要等待拿到资源以后再返回方法, 但有些函数并没有提供同步版本(比如request模块), 你要怎么让一个异步的函数变成同步执行?

也许你想到了async和await. 首先给结论, async和await并没有解决这个问题, 看如下代码:

console.log('out 1');

async function f() {
await new Promise((resolve) => {
console.log('inner 1');
setTimeout(resolve, 500)
console.log('inner 2');
}).then(() => {
console.log('inner 3');
});
}

console.log('out 2');
f();
console.log('out 3');

你猜猜输出是啥?答案是:
out 1
out 2
inner 1
inner 2
out 3
inner 3

所以函数外部会直接运行, async和await保证了函数内的代码按顺序进行, 但对方法外的顺序无能为力.

也许你想到了使用sleep, 使用一个循环, 每次都去检查一个外部变量, 使用主动的方式去和异步方法保持同步. 但很可惜, 这行不通, 因为nodejs没有提供sleep这个方法. 你唯一的办法可能是用async和await来包装setTimeout方法, 使用曲线救国的方式来实现sleep.

总之, 这十分丑陋而且怪异, 我现在的办法是用deasync这个模块, 来让异步方法强行同步化. 至于它的底层原理, 我猜也是用async和await来包装setTimeout.

我对es6不满意的地方就是它发明了Promise, 但没有彻底异步的问题, 他的设计很先进, 但很多时候真的就是只想要一个最简单的 await result = request(url); 或者 sleep(100);