You Don't Know JS: Async & Performance(第2章,Callbacks)
Chapter 2: Callbacks.
Callbacks are by far the most common way that asynchrony in JS programs is expressed and managed.
Indeed, the callback is the most fundamental async pattern in the language.
对于JS来说,回调函数是异步工作的马,它很好地完成它的任务,除了。。。.
callbacks有它的缺点。许多开发者喜欢promise是最好的异步模式。
但是如果你不了解什么是抽象概念,你不可能有效使用任何抽象概念。
Continuations 继续延伸
回调函数包裹或封装了程序的continuations.
// A
setTimeout( function(){
// C
}, 1000 );
// B
准确的理解这段代码:执行A, 建立一个timer(1秒后激活),然后执行B, 然后1秒到后执行C.
程序的执行顺序,和开发者正常的大脑思考顺序的不同,造成了代码的不易理解。
理解回调作为异步表达式的缺陷是非常关键的。
2个大缺陷:
- 大脑思考方式和JS异步代码的执行的冲突。导致难以维护,容易忽视导致错误。
- 回调导致信任链条的割断,每个回调都必须加验证。而使用第三方API会导致不可知问题。
Sequential Brain
作者见到不少人说自己是multitasker,意思是同时干多件事情。作者认为这是很危险的,就像开车时发短信。 texting while driving
我们的大脑有并行处理事情的功能吗?答案是不能。
当我们fake multitasking,其实更像是快速的上下文转换!因为速度非常快,从外在看起来就像是同步地平行的做多个事情。
Doing Versus Planning
大脑可以做类似同步思考事情。但实际上的做事情,需要有顺序。
We think in step-by-step terms, but the tools (callbacks) available to us in code are not expressed in a step-by-step fashion once we move from synchronous to asynchronous.
And that is why it's so hard to accurately author and reason about async JS code with callbacks: because it's not how our brain planning works.
难以理解异步代码和回调是因为人类的大脑计划工作的方式。
Nested/Chained Callbacks
也叫做回调地狱或者pyramid of doom。
That's the first major deficiency to articulate about callbacks: they express asynchrony in code in ways our brains have to fight just to keep in sync with (pun intended!)
回调的第一个主要缺陷:回调在代码中表现是异步的,而在我们的大脑中不得不保持同步。
Trust Issues
大脑的序列化思考方式和JS代码的异步驱动回调之间的不匹配仅仅是关于回调问题的一部分。
还有更多的问题。
比如和第三方程序的配合。
当你把你的部分程序的执行的控制权交给第三方,叫做inversion of control。这里就有一个不能言说的合同存在于你的代码和第三方插件之间。
Tale of Five Callbacks
一个故事,网络卖电视,信用卡支付环节的功能交给第三方,并使用回调函数等待支付。结果第三方的代码出现了问题。导致客户一共支付了5次。
Not Just Others' Code
即使不使用第三方,使用自己控制开发的API.但是:
So, contemplate this: can you even really trust utilities that you do theoretically control (in your own code base)?
Think of it this way: most of us agree that at least to some extent we should build our own internal functions with some defensive checks on the input parameters, to reduce/prevent unexpected issues.
例如:
function addNumbers(x,y) {
// + is overloaded with coercion to also be
// string concatenation, so this operation
// isn't strictly safe depending on what's
// passed in.
return x + y;
} addNumbers( 21, 21 ); //
addNumbers( 21, "21" ); // "2121"
所以需要写防御性核查/转化。
//加上判断
if (typeof x != "number" || typeof y != "number") {
throw Error( "Bad parameters" );
} //或者直接转化格式
x = Number( x );
y = Number( y );
信任但是要确认(核查)。
回调函数不会援助我们任何事情,我们不得的自己建造这些核查机制。
我们不得不在每个单独的异步回调中重复的做核查。
回调最麻烦的问题是“控制转化”导致所有信任链的割断!
Trying to Save Callbacks
本节讲解几个回调的改进模式。
1.split-callback design(ES6 Promise使用了这个模式)
split-callback design is what the ES6 Promise API uses。
提供success,failure2个回调函数。
2. error-first style(Node style用在Node.js)
第一个参数储存一个错误对象,通过判断这个参数是否是empty/falsy来选择使用哪个结果。
function response(err,data) {
// error?
if (err) {
console.error( err );
}
// otherwise, assume success
else {
console.log( data );
}
} ajax( "http://some.url.1", response );
但是上面2个模式,仍然需要观察!
首先,没有真正解决信任问题。没有防止/过滤不想要的重复内容。更严重的是,你可能同时得到成功和失败信号,或者什么都没有,因此你不得不自己写条件判断。
并且,因为没有复用,你需要在每个单独的回调中写上过滤/防御代码。
问题:
What about the trust issue of never being called?
如果没有发生回调被调用的情况,你需要建立一个timeout来取消这个事件。
问题:
还有另外的信任问题是,回调函数被调用的太早!这个例子就显示了不确定性:
function result(data) {
console.log( a );
} var a = 0; ajax( "..pre-cached-url..", result );
a++;
最终打印0/1, 不确定。因为异步回调可能发生的很快,导致输出0.
因此需要加上判断函数 ajax( "..pre-cached-url..", asyncify( result ) );
因为以上的这些问题,你不得不花费大量努力时间去解决!
幸运来了!ES6来了!
Review
回调是JS异步 的基础单元!但它有很多问题
第一, 我们的大脑计划事情是序列的,块的,单线程的方式。但是回调表达异步的流是非序列的,非线性的。如果你看别人的代码就很困难。
Bad to reason about code is bad code that leads to bad bugs.
我们所需要的是,把异步用更同步,序列,块方式表示出来,就像我们的大脑思考一样。
第二, 这是更重要地,回调会遭遇控制转化。这种控制转化导致了一系列信任问题。
使用援助逻辑来解决这些信任问题是可以的,但是这很麻烦也难以维护代码,并且bug是后知后觉的,难以预防,而一旦出错就是巨大的损失。(风险是未知的,代码不能得到充足的保护,直到你被这些bug咬到!)
所以,需要有一个全面的信任解决方案,可以反复在多个我们创建的回调中使用,无需重复写在回调代码中。
我们需要比回调更好的解决方案! 未来的JS要求更精明的并且能够异步模式。后续章节将深挖这些冒出来的进化!!
You Don't Know JS: Async & Performance(第2章,Callbacks)的更多相关文章
- You Don't Know JS: Async & Performance(第一章, 异步:now & later)
Chapter 1: Asynchrony: Now & Later 在一门语言中,比如JavaScript, 最重要但仍然常常被误解的编程部分是如何在一个完整的时间周期表示和操作程序行为. ...
- You Don't Know JS: Async & Performance(第3章, Promises)(未看)
Chapter 3: Promises But what if we could uninvert that inversion of control? What if instead of hand ...
- JavaScript 数据访问(通译自High Performance Javascript 第二章) [转]
JavaScript 数据访问(通译自High Performance Javascript 第二章) JavaScript 数据访问(翻译自High Performance Javascript ...
- Node.js——Async
一:流程控制 为了适应异步编程,减少回调的嵌套,我尝试了很多库.最终觉得还是async最靠谱. 地址:https://github.com/caolan/async Async的内容分为三部分: 流程 ...
- Async Performance: Understanding the Costs of Async and Await
Stephen Toub Download the Code Sample Asynchronous programming has long been the realm of only the m ...
- Js高设笔记1-2章 defer and async
1,js是由ECMAscript ,dom ,bom组成的专为网页交互而设计的脚本语言.js是脚本语言之一. 2,MIME,是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的 ...
- [node.js] async/await如何优雅处理异常?
node.js的世界,从callback开始,不会止于async. 所有人都在骂为什么不能完全进化,其实我感觉这就是老外的细心,为了承上.这也就是为什么async其实就是promise一样,假如不是一 ...
- js async await 终极异步解决方案
既然有了promise 为什么还要有async await ? 当然是promise 也不是完美的异步解决方案,而 async await 的写法看起来更加简单且容易理解. 回顾 Promise Pr ...
- node.js async 几个函数
async.waterfallasync.seriesasync.parallelasync.auto http://my.oschina.net/huangsz/blog/176203http:// ...
随机推荐
- jsoup对 HTML 文档的解析和操作
本文手动转载自http://www.cnblogs.com/chenying99/archive/2013/01/04/2844615.html,仅根据个人需要对实用部分进行转载,详细请阅读原文. j ...
- topcoder srm 706 div1
1.给定一个迷宫,点号表示不可行,井号表示可行.现在可以改变其中的一些井号的位置.问最少改变多少个井号可以使得从左上角到右下角存在路径. 思路:设高为$n$,宽为$m$,若井号的个数$S$小于$n+m ...
- Python3 tkinter基础 Canvas delete 删除画布中的所有图形
Python : 3.7.0 OS : Ubuntu 18.04.1 LTS IDE : PyCharm 2018.2.4 Conda ...
- MongoDB 创建索引及其他
索引 以提升查询速度 测试:插入十万条数据到数据库中 for(i=0;i<100000;i++){db.t255.insert({name:'test'+i,age:i})} db.t1.fin ...
- Why database migrations?
https://flywaydb.org/getstarted/why First, let's start from the beginning and assume we have a proje ...
- (zhuan) Recurrent Neural Network
Recurrent Neural Network 2016年07月01日 Deep learning Deep learning 字数:24235 this blog from: http:/ ...
- (zhuan) Speech and Natural Language Processing
Speech and Natural Language Processing obtain from this link: https://github.com/edobashira/speech-l ...
- @PathVariable与@RequestBody的区别,及前段请求接口的写法。
@PathVariable 1:接受参数时,地址栏为:/{args1}/{args2} 2:用法:(@PathVariable(value = "args")Long id) 3 ...
- MS-Windows中的Git命令行
Git command line for MS-Windows Inhalt 1 Download and install, or copy the git command line suite fo ...
- 【Java】【存储&作用域】
[存储] 1. 寄存器.这是最快的保存群裕,因为它位于和其他所有保存方式不同的地方:处理器内部.然而,寄存器的数量有限,所以寄存器是根据需要由编译器分配.我们对此没有直接的控制权,也不可能在自己的程序 ...