Linus Torvalds:
If you need more than 3 levels of indentation, you ’ re screwed anyway, and should fix your program.
如果你的代码里需要有超过三层的缩进,那么你已经搞砸了,应该修改你的代码。
这里贴一段我写的代码
function do_kcptun_update(btn) {
btn.disabled = true;
btn.value = '<%:Downloading...%>';
add_remove_page_notice(true);
var kcptun_update_url = '<%=dsp.build_url("admin/services/kcptun/update/kcptun")%>';
(new XHR()).get(kcptun_update_url, {
token: token_str,
url: kcptun_info ? kcptun_info.url.download : ''
}, function (x, json) {
if (x && x.status == 200) {
if (json.code == 0) {
btn.value = '<%:Extracting...%>';
(new XHR()).get(kcptun_update_url, {
token: token_str,
task: "extract",
file: json.file,
subfix: kcptun_info ? kcptun_info.type : ''
}, function (x, json) {
if (x && x.status == 200) {
if (json.code == 0) {
btn.value = '<%:Moving...%>';
(new XHR()).get(kcptun_update_url, {
token: token_str,
task: "move",
file: json.file
}, function (x, json) {
if (x && x.status == 200) {
if (json.code == 0) {
on_update_success(btn);
} else {
on_request_error(btn, json);
}
} else {
on_request_error(btn);
}
});
} else {
on_request_error(btn, json);
}
} else {
on_request_error(btn);
}
});
} else {
on_request_error(btn, json);
}
} else {
on_request_error(btn);
}
});
}
这是一段用来更新程序的 JavaScript,但是代码的继续执行依赖于上一次请求的成功执行。 可苦于没有好的优化方案,只能写出这种垃圾代码了。
稍微优化了一下,感觉能看一点了:GitHub
1
hkllzh 2018-05-03 14:54:14 +08:00
Rx
|
2
sunny352787 2018-05-03 14:55:27 +08:00 1
最简单的,反过来判断不就行了
|
3
kuoruan OP @sunny352787 #2 具体如何?
|
4
hcymk2 2018-05-03 14:57:42 +08:00
首先不再使用匿名函数。之后再找个对付回调地狱轮子
|
5
Luckyray 2018-05-03 14:58:01 +08:00
重构,封装成函数
|
6
PressOne 2018-05-03 14:59:32 +08:00 via Android
有的时候多层嵌套少不了 ,不用故意减少。按实际的逻辑表现即可,你这个看起来也确实多了点
|
8
noli 2018-05-03 15:05:03 +08:00 via iPhone
你需要使用 c#或者像 c#那样提供 yield return 并且提供像 select 和 select many 把深层次数据提取代码 压扁的语法糖
|
9
Phariel 2018-05-03 15:05:32 +08:00
Promise
|
10
glacer 2018-05-03 15:07:42 +08:00
Promise 或 async/await 了解一下
|
11
widdy 2018-05-03 15:12:15 +08:00
|
12
siteshen 2018-05-03 15:14:35 +08:00 4
楼上说的“最简单的,反过来判断不就行了”,其实说的是 `early return`。
其他的回答 Promise async/await 等完全是另外一个话题。 按照这个思路重构代码会清晰很多,刚刚写了个例子供参考。 ```js // origin source code function doSomething() { if (cond1) { success1(); if (cond2) { success2(); if (cond3) { success3(); } else { fail3(); } } else { fail2(); } } else { fail1(); } } function betterDoSomething() { if (!cond1) { fail1(); return; } success1(); if (!cond2) { fail2(); return; } success2(); if (!cond3) { fail3(); return; } success3(); } ``` |
13
Immortal 2018-05-03 15:16:05 +08:00
|
15
autoxbc 2018-05-03 15:18:30 +08:00
Promise +1
另外,(new XHR()).get... 这种多余的括号看着真难受 |
17
DOLLOR 2018-05-03 15:23:21 +08:00
Promise,Babel 和 TypeScript 都支持 es3 target 的。
如果不想用 ES6 语法,就用 async.js 。 |
18
crab 2018-05-03 15:27:38 +08:00
if (x && x.status != 200)
XXXXX |
19
RicardoScofileld 2018-05-03 15:28:29 +08:00
最简单的反向判断啊,if ...,你改成 if not ... 不就好咯嘛
|
20
loveCoding 2018-05-03 16:03:19 +08:00
反向判断+++1
|
21
zn 2018-05-03 16:07:08 +08:00 via iPhone 2
短路疗法了解一下。
其实就是楼上说的反向判断啦,先判断不符合条件的,尽快返回,后面剩下合法条件再做处理。 |
22
GoLand 2018-05-03 16:07:56 +08:00 1
early return.
|
23
qiumaoyuan 2018-05-03 16:16:07 +08:00
|
24
evitceted 2018-05-03 16:22:48 +08:00
rx
|
25
yongjing 2018-05-03 16:25:52 +08:00
callback hell
|
26
sampeng 2018-05-03 16:48:45 +08:00
封装成函数+promise 可以解决问题。。但 promise 也可能陷入调用链太长的问题。总比这样强不是。
楼上有说封装成函数没减少层级。有些逻辑是没办法减少的。但封装函数最少一眼能看明白逻辑,让代码清晰可见的最终目的不就是可读性尚可。 early return 也是一个很好的手段。稍微减少一些不必要判断层级。 唔。。少用匿名函数。。简直是噩梦 |
27
pluschen 2018-05-03 16:56:22 +08:00
啥?封装成函数没减少层数?
别逗,哪有什么层数?都是 JMP。 |
28
sampeng 2018-05-03 16:58:58 +08:00
仔细看了代码。。只是各种 else 处理错误而已。。。这个。。很难吗?
|
29
xiaojunjor 2018-05-03 17:02:32 +08:00
|
31
zhlssg 2018-05-03 17:16:50 +08:00
async await ,提早 return
|
32
saulshao 2018-05-03 17:19:49 +08:00
If you need more than 3 levels of indentation, you ’ re screwed anyway, and should fix your program.
这句话本来就是说的是一个函数里面的事情。 |
33
cs923 2018-05-03 17:31:50 +08:00
RxJs(没用过 应该能解决)
|
34
Justin13 2018-05-03 18:21:09 +08:00 via Android
就嵌套而言,可以考虑 early return,抽函数,就业务而言,可以考虑使用更优雅的库,promise,async
|
35
we2ex 2018-05-03 18:23:59 +08:00 via Android
@xiaojunjor #29 正解,第一时间想到的也是这篇文章
|
36
banricho 2018-05-03 18:25:14 +08:00
这个代码的根本原因在于直接原生 XHR …
不用任何库的情况下,封装一个 fetch 剩下是处理异步的问题,楼上都说了 最后才是 if 的问题 |
37
wlwood 2018-05-03 18:42:50 +08:00
其实,感觉,用 react.js, vue 这些框框,这种地狱应该挺好解决啊
|
38
noNOno 2018-05-03 20:08:10 +08:00
歪个楼,动感光波?
|
39
Exia 2018-05-03 20:14:50 +08:00
楼主的地狱回调,能自己看懂就还不错了,应该用 promise 吧,我也要向这个方面提升一下。
|
40
LevineChen 2018-05-03 20:22:12 +08:00 via iPhone
多个 return 也不好 可以用 do while ( false ) break 实现类似功能
|
41
xpol 2018-05-03 22:19:51 +08:00
GraphQL 了解一下。
|
42
xpol 2018-05-03 22:23:05 +08:00
我以为都是从服务器请求数据:),请忽略我上一条回复。
|
43
mingyun 2018-05-03 23:47:44 +08:00
提前 return
|
44
pepesii 2018-05-04 08:41:10 +08:00 via iPhone
我记得上初中的时候,数学老师经常说的一句话是,“正难则反”,于是我在碰到真值条件复杂的时候,就找假条件先处理,提前返回。
|
45
crayygy 2018-05-04 09:51:41 +08:00
打开帖子以前看到标题的第一反应就是 JS 的回调地狱...
|
46
th00000 2018-05-04 09:59:27 +08:00
快速失败原则
|
47
ikaros 2018-05-04 10:03:53 +08:00
你这样写以后再来看不觉得麻烦吗?
|
48
SakuraKuma 2018-05-04 10:19:07 +08:00
Promise 啊。
kcptun.download().then(extract).then(move).catch(onError) |
49
f0rger 2018-05-04 11:33:10 +08:00
大概长这样,没调,可能有语法和写法错误:
https://gist.github.com/luoweihua7/58b884ce7ecd618bb27fbe8fa9b4cf72 |
50
zhuweiyou 2018-05-04 12:10:19 +08:00
一个是用 async / await
一个是先 return 错误的,就不会嵌套多层了 |
51
bangbaoshi 2018-05-04 15:30:16 +08:00
·····
if (cond1) { if (cond2) { if (cond3) { do something } } } ····· 改成 ····· if(!cond1) { return; } if(!cond2) { return; } if(!cond3) { return; } do something ····· |