众所周知,在node.js经常要调用一些异步的方法,通过回调函数获取数据,然后必须在这个回调函数里进行下一步的处理。这样,很容易就落入“回调地狱”,即很可能写出层层嵌套的回调函数,这倒还不是什么大问题,通过一些编程技巧就可以解决。“回调地狱”真正可怕的是,不能保证这个回调函数会不会执行、会执行几次,这样就相当于把程序的控制权转移出去了,程序的安全性和可靠性大大降低。所以,Promise诞生了,解决了这几个棘手的问题。 然而,使用Promise还是会遇到一些问题的。最常见的一个问题是,想中断Promise链:
promiseA.then(function(data) {
if (something) {
// to break
}
else {
return promiseB;
}
}).then(function(data) {
// doing something
}).then(null, console.log);
如果想中断,只能是抛出异常,但这是正常结束,不合逻辑;或是嵌套:
promiseA.then(function(data) {
if (something) {
// to break
}
else {
return promiseB.then(function(data) {
// doing something
});
}
}).then(null, console.log);
一个分支的情况下还好办,但如果再复杂些,就要嵌套多层了。
还有一个比较麻烦的就是代码组织的问题。很多时候,其实都希望异步获取到的数据和处理过程是看作一步的,但使用Promise就需要不间断地组成Promise链一直then下去,让一个过程变得很长。如果说把then中的回调函数抽出来写,那就更难维护了,因为会变成这样:
var thenA = function(dataA) {
// doSomething
// 处理完A的数据后,就必须莫名奇妙地返回一个下一步的Promise
// 尽管这很可能会与dataA有联系,但还是会感觉很奇怪的
// 这是因为这个函数做了两件关联不太事:处理数据,然后执行一个异步过程,等待下一步处理
return promiseB;
};
promiseA.then(thenA).then(function(dataB) {}).then(null, console.log);
总之,在一个函数里似乎是不太方便同时写获取数据并处理的过程,要放到下一个then去处理,使得这些Promise难解难分,会出现一大段没法解耦的代码。
还有一个问题,就是复杂的流程控制。虽然有一些像Q这样的库提供了并发处理多个Promise的方法,让Promise做简单的顺序和并发流程不成问题,但是如果复杂一点,例如有一些条件分支,还有循环等,就得再临时创建一些Promise了,代码量就变大了。
为了解决上述问题,我尝试性地写了一个库:magic-task,在这里和大家分享,希望可以给大家带来方便。
虽然现在是generator的时代了, 还是赞一下
if else 嵌套,这些编程最基本的东西,在nodejs里面搞得跟天书一样
@Pana 确实是,有了generator好多了,这是我在不使用generator的情况做的最后的挣扎~
@yakczh 异步回调好头疼~
我感觉还是generator治本,其他方法还是很容易就掉到地狱里
@iMumuMua @yakczh 你好,我花2年的功夫思考并设计了一门新的语言lix,它最终把代码编译成js,用nodejs运行,我觉得很好的解决了这个问题。这是我项目的github地址: https://github.com/lixinqi/lix。希望不会让你失望:-)
sleep := [ms]->{
cc call [brk]->{
ms timeout []->{
brk call
}
}
}
i := 0
while (i < 10) {
20 sleep
i print
i = i + 1
}
'end' print
看来我说天书,一点都没说错
sas callback 18层毫无压力.
mark
@yakczh 我再把它写成中文,这样更没节操一点:-)
暂停 := [ms]->{
当前续点 执行 [继续]->{
ms 毫秒超时后 []->{
继续 执行
}
}
}
毫秒 := [i]->{i}
i := 0
while (i < 10) {
20 | 毫秒 | 暂停
i 打印到终端
i = i + 1
}
'end' 打印到终端
它真的能把异步的setTimeout在代码逻辑上变成同步的函数
不要在意语法细节 :-)
有人能看懂上面的代码吗?