Javascript中的异步与性能(二) -- 回调

回调是编写和处理 JavaScript 程序异步逻辑的最常用方式。

回调的信任问题:

思考一下代码

function result(data) { 
	console.log( a ); 
} 
var a = 0; 
ajax( "..pre-cached-url..", result ); 
a++;

这段代码会打印出 0(同步回调调用)还是 1(异步回调调用)呢?这要视情况而定。

//转化为异步调用工具
function asyncify(fn) { 
	var orig_fn = fn, 
	intv = setTimeout( function(){ 
		intv = null; 
		if (fn) fn(); 
	}, 0 ); 
	fn = null; 
	return function() { 
		// 触发太快,在定时器intv触发指示异步转换发生之前?
		if (intv) { 
			fn = orig_fn.bind.apply( 
				orig_fn, 
				// 把封装器的this添加到bind(..)调用的参数中,
				// 以及克里化(currying)所有传入参数
				[this].concat( [].slice.call( arguments ) ) 
			); 
		} 
		// 已经是异步
		else { 
			// 调用原来的函数
			orig_fn.apply( this, arguments ); 
		} 
	}; 
}
/**调用代码**/
function result(data) { 
	console.log( a ); 
} 
var a = 0; 
ajax( "..pre-cached-url..", asyncify( result ) ); 
a++;

不管这个 Ajax 请求已经在缓存中并试图对回调立即调用,还是要从网络上取得,进而在将来 异步完成,这段代码总是会输出 1,而不是 0——result(…) 只能异步调用,这意味着 a++ 有机会在 result(…) 之前运行。
“解决”了一个信任问题!但这是低效的,而且也会带来膨胀的重复代码,使你的项目变得笨重。

总结

回调函数是 JavaScript 异步的基本单元。但是随着 JavaScript 越来越成熟,对于异步编程领域的发展,回调已经不够用了。
第一,大脑对于事情的计划方式是线性的、阻塞的、单线程的语义,但是回调表达异步流程的方式是非线性的、非顺序的,这使得正确推导这样的代码难度很大。难于理解的代码是坏代码,会导致坏 bug。
我们需要一种更同步、更顺序、更阻塞的的方式来表达异步,就像我们的大脑一样。
第二,也是更重要的一点,回调会受到控制反转的影响,因为回调暗中把控制权交给第三方(通常是不受你控制的第三方工具!)来调用你代码中的 continuation。这种控制转移导致一系列麻烦的信任问题,比如回调被调用的次数是否会超出预期。
可以发明一些特定逻辑来解决这些信任问题,但是其难度高于应有的水平,可能会产生更笨重、更难维护的代码,并且缺少足够的保护,其中的损害要直到你受到 bug 的影响才会被发现。
我们需要比回调更好的机制。到目前为止,回调提供了很好的服务,但是未来的 JavaScript需要更高级、功能更强大的异步模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Funnee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值