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:// ...
随机推荐
- 使用Selenium+Java+Juint实现移动web端自动化的代码实现
浏览器: Chrome 首先通过developer模式查看Chrome浏览器支持哪些手机,如图: 在代码中使用ChromeOptions对象的addArguments方法来设置参数,如下代码所示: p ...
- matlab做聚类分析
说明:如果是要用matlab做kmeans聚类分析,直接使用函数kmeans即可.使用方法:kmeans(输入矩阵,分类个数k). 转载一: MATLAB提供了两种方法进行聚类分析: 1.利用 clu ...
- SCU 4437 Carries(二分乱搞)题解
题意:问任意两对ai,aj相加的总进位数为多少.比如5,6,95分为(5,6)(5,95)(6,95),进位数 = 1 + 2 + 2 = 5 思路:显然暴力是会超时的.我们可以知道总进位数等于每一位 ...
- hexo在github和coding.net部署并分流(一)
安装GIT和Node.JS 首先在自己的电脑上安装好git和node.js,这一步怎么做自己搜索,安装软件都是下一步下一步,应该不难,GIT安装完成后打开git cmd输入 git config -- ...
- P5091 【模板】欧拉定理
思路 欧拉定理 当a与m互质时 \[ a^ {\phi (m)} \equiv 1 \ \ (mod\ m) \] 扩展欧拉定理 当a与m不互质且\(b\ge \phi(m)\)时, \[ a^b \ ...
- P2604 [ZJOI2010]网络扩容
思路 简单的费用流问题,跑出第一问后在残量网络上加边求最小费用即可 代码 #include <cstdio> #include <algorithm> #include < ...
- Images之base image
Create a base image Most Dockerfiles start from a parent image. If you need to completely control th ...
- communication
Always consider the challenge as a chance. Basic principles: Know your audience. Know your purpose. ...
- Latex: 保持参考文献大小写
参考: BibTeX loses capitals when creating .bbl file Latex: 保持参考文献大小写 在排版时,BibTeX会根据参考文献的格式将除了title中的第一 ...
- python bytes类型
python3中二进制数据则由bytes类型表示,8位一字节 格式化打印文件的二进制编码 with open('spiderman.mkv', "rb") as f: print( ...