第一部分 类型和语法
第二部分 异步和性能
2.1 continuation
让我们回到第 1 章中给出的异步回调的例子,为了突出重点,以下稍作了修改:
// A ajax( "..", function(..){ // C } ); // B
// A 和 // B 表示程序的前半部分(也就是现在 的部分),而 // C 标识了程序的后半部分(也就是将来 的部分)。前半部分立刻执行,然后是一段时间不确定的停顿。在未来的某个时刻,如果 Ajax 调用完成,程序就会从停下的位置继续执行后半部分。
换句话说,回调函数包裹或者说封装了程序的延续(continuation)。
让我们进一步简化这段代码:
// A setTimeout( function(){ // C }, 1000 ); // B
请在这里稍作停留,思考一下你自己会如何(向对 JavaScript 运作机制不甚了解的某位人士)描述这段程序的运行方式。然后试着把你的描述大声说出来。这有助于你理解我接下来要展示的要点。
大多数人刚才可能想到或说出的内容会类似于“执行 A,然后设定一个延时等待 1000 毫秒,到时后马上执行 C”。你的描述准确度如何呢?
也可能进一步修改为“执行 A,设定延时 1000 毫秒,然后执行 B,然后定时到时后执行 C”。这比第一个版本要更精确一些。你能指出其中的区别吗?
尽管第二个版本更精确一些,但是在匹配大脑对这段代码的理解和代码对于 JavaScript 引擎的意义方面,两个版本对这段代码的解释都有不足。这种不匹配既微妙又显著,也正是理解回调作为异步表达和管理方式的缺陷的关键所在。
一旦我们以回调函数的形式引入了单个 continuation(或者几十个,就像很多程序所做的那样!),我们就容许了大脑工作方式和代码执行方式的分歧。一旦这两者出现分歧(这远不是这种分歧出现的唯一情况,我想你明白这一点!),我们就得面对这样一个无法逆转的事实:代码变得更加难以理解、追踪、调试和维护。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论