如何才能减少代码的嵌套层级?

2018-05-03 14:51:44 +08:00
 kuoruan

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,但是代码的继续执行依赖于上一次请求的成功执行。 可苦于没有好的优化方案,只能写出这种垃圾代码了。

7033 次点击
所在节点    程序员
51 条回复
hkllzh
2018-05-03 14:54:14 +08:00
Rx
sunny352787
2018-05-03 14:55:27 +08:00
最简单的,反过来判断不就行了
kuoruan
2018-05-03 14:57:36 +08:00
@sunny352787 #2 具体如何?
hcymk2
2018-05-03 14:57:42 +08:00
首先不再使用匿名函数。之后再找个对付回调地狱轮子
Luckyray
2018-05-03 14:58:01 +08:00
重构,封装成函数
PressOne
2018-05-03 14:59:32 +08:00
有的时候多层嵌套少不了 ,不用故意减少。按实际的逻辑表现即可,你这个看起来也确实多了点
kuoruan
2018-05-03 15:01:52 +08:00
@Luckyray #5 封装成函数并没有事实上减少嵌套层级
noli
2018-05-03 15:05:03 +08:00
你需要使用 c#或者像 c#那样提供 yield return 并且提供像 select 和 select many 把深层次数据提取代码 压扁的语法糖
Phariel
2018-05-03 15:05:32 +08:00
Promise
glacer
2018-05-03 15:07:42 +08:00
Promise 或 async/await 了解一下
widdy
2018-05-03 15:12:15 +08:00
@kuoruan
@sunny352787 意思是先判断 else 逻辑,把 else 提前 return;
siteshen
2018-05-03 15:14:35 +08:00
楼上说的“最简单的,反过来判断不就行了”,其实说的是 `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();
}
```
Immortal
2018-05-03 15:16:05 +08:00
@kuoruan
回你 7l
感觉你有点钻牛角尖了.重构和封装的确不会直接减少嵌套和层级,但是我们做的这些能直接提高代码可读性.
而且你那个看起来好像可以用抛出异常的方式处理
kuoruan
2018-05-03 15:17:04 +08:00
@glacer #10 为了兼容性,用不了 ES6
autoxbc
2018-05-03 15:18:30 +08:00
Promise +1

另外,(new XHR()).get...
这种多余的括号看着真难受
kuoruan
2018-05-03 15:19:19 +08:00
@Immortal #13 这确实是个好方法
DOLLOR
2018-05-03 15:23:21 +08:00
Promise,Babel 和 TypeScript 都支持 es3 target 的。

如果不想用 ES6 语法,就用 async.js 。
crab
2018-05-03 15:27:38 +08:00
if (x && x.status != 200)
XXXXX
RicardoScofileld
2018-05-03 15:28:29 +08:00
最简单的反向判断啊,if ...,你改成 if not ... 不就好咯嘛
loveCoding
2018-05-03 16:03:19 +08:00
反向判断+++1

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/451758

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX