Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
javascript异步编程探索.pdf
Search
lichen
March 18, 2013
3
1.6k
javascript异步编程探索.pdf
lichen
March 18, 2013
Tweet
Share
More Decks by lichen
See All by lichen
成长记录系统改版方案
lichen
0
1.4k
tear
lichen
0
1.4k
Featured
See All Featured
Practical Orchestrator
shlominoach
186
10k
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
0
97
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
250
21k
Visualization
eitanlees
145
15k
RailsConf 2023
tenderlove
29
900
How to Think Like a Performance Engineer
csswizardry
20
1.1k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
65k
Measuring & Analyzing Core Web Vitals
bluesmoon
4
130
Into the Great Unknown - MozCon
thekraken
32
1.5k
What's in a price? How to price your products and services
michaelherold
243
12k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Designing Experiences People Love
moore
138
23k
Transcript
JavaScript 异步编程探索 var KEYWORDs = { author: “李诚”, } date:
“2013/3/18”, alias: “使用消息触发、Promise/A、二次编译提升异步编程体验” , E-mail: “
[email protected]
”
var 目录 = { } • javascript异步编程简介 • javascript异步编程优化:
消息触发 Promise/A 二次编译 • 分析总结
var 预期 = { } • 了解JS中异步回调引发的问题 • 理解针对该问题提出的三种优化方案 •
在实际编程过程中,在某些具体情况 下引入某种解决方案 • Open our mind
var JS异步编程简介 = { } 1. 异步和同步之别 2. JS异步的必要性 3.
异步导致的问题
var 同步和异步 = { } 异步:任务分割 同步:顺序执行,等待,阻塞
var 同步和异步 = { } function synFn() { var i
= 0; while(i < 10000) { i++; } return i; } function asynFn(i) { i = i || 0; if(i <= 10000) { setTimeout(function() { i++; asynFn(i); }, 100) } return i; }
var JS异步执行的操作 = { } • Ajax(XMLHttpRequest) • setTimeout/setInterval •
CSS3 Transition/Animation • postMessage • Web Workers • Web Sockets • and more… 所有耗时的操作都应进行分解异步执行
var JS异步操作的必要性 = { } 原因:单线程(?) ->排队模式->事件队列 必要性: 防止阻塞: UI更新、事件监听、用户操作
异步重要武器:回调函数
var JS回调函数 = { } 异步编程条件下控制程序的执行流程 回调是JS异步编程模式下能够顺利进 行的必要条件
var JS回调函数 = { } 把函数当多参数传递,并在另一个 函数中执行传递进来的函数 var fn =
function(fn1, fn2, fn3) { fn1(); fn2(); fn3(); }
var JS回调函数 = { } 把函数当多参数传递,并在另一个 函数中执行传递进来的函数 var fn =
function(fn1, fn2, fn3) { fn1(); fn2(); fn3(); }
var JS异步编程的问题 = { } 保证A、B、C、D、E方法顺序执行 同步执行时: A(); B(); C();
D(); E(); 异步时: A(function() { B(function() { C(function() { D(function() { E(); }); }); }); });
var JS异步编程的问题 = { } 来自 https://github.com/christkv/node-mongodb-native/blob/master/examples/blog.js 爱上嵌套需要很 多年,讨厌嵌套 只需要一段这样
的代码…… 感觉不会再爱了
var JS异步编程的问题 = { } 这个世界上不存在所谓回调函数深度嵌套的问题。 —— Jackson Tian 世界上本没有嵌套回调,写得人多了,也便有了}}}}}}}}}}}}。
—— fengmk2 所有回调函数深度嵌套的行为都是耍流氓。
var JS异步编程的问题 = { } • 代码结构支离破碎 • 可读性降低,提高的代码的复杂度 •
对回调的严重依赖 • 非线性的适应
var JS异步编程的问题 = { } • 代码结构支离破碎 • 可读性降低,提高的代码的复杂度 •
对回调的严重依赖 • 非线性的适应 流程混乱、编程体验糟糕
var JS异步编程优化方案 = { } 1.消息触发 2.PROMISE/A 3.二次编译
var JS异步编程优化 = { } 消息触发: 将函数依赖关系先进行声明,并在函数执行完 毕时发出执行完毕的消息,如果依赖函数都发 出执行完毕的消息,则该依赖函数开始执行 代表:EventProxy.js
var 消息触发 = { } var proxy = new EventProxy();
proxy.assign( 'A', 'B', 'C', D ); A ( function() { proxy.trigger( 'A' ); }); B ( function() { proxy.trigger( 'B' ); }); C ( function() { proxy.trigger( 'C' ); });
var 消息触发 = { } 优点:实现简单,较易理解,并有效解决 了某些时候函数深度嵌套的问题,同时能 降低代码的耦合度 缺点:需要显式的书写函数依赖声明代码
var Promise/A = { } CommonJS提出的异步编程模型规范 A promise is defined
as an object that has a function as the value for the property ‘then‘. then(fulfilledHandler, errorHandler, progressHandler) then方法返回另一个promise对象,形成promise管道 目的: 提供统一的异步编程API规范
var Promise/A = { } 一个Promise/A规范的实现提供如下的编程体验: promise.then(done, fail, progress).then(…).then(…) Promise的三种状态:
[unfulfilled, fulfilled, failed] 实现:when.js、Dojo/Deferred.js、$.Deferred、 WinJS.Promise (win8 metro)
var Promise/A参数传递 = { } • resolve(param) -> fulfilledHandler(param) •
reject(param) -> errorHandler(param) 通过promise的resolve和reject方法来向后 传递参数
var jQuery deferred = { } $.Deferred: Jquery 1.5版本基于Promise/A规范实现 应用:
$.ajax返回对象的变更: <1.5:$.ajax方法返回XHR对象 >=1.5:$.ajax返回$.deferred对象
var $.Deferred使用示例 = { } 普通青年一般都这样写Ajax请求: $.ajax({ url: "test.html", success:
function() { alert("哈哈,成功了!"); }, error: function() { alert("出错啦!"); } });
var $.Deferred使用示例 = { } 普通青年一般都这样写Ajax请求: $.ajax({ url: "test.html", success:
function() { alert("哈哈,成功了!"); }, error: function() { alert("出错啦!"); } });
var $.Deferred使用示例 = { } $.ajax("test.html") .done(function() { alert("哈哈,成功了!"); })
.fail(function() { alert("出错啦!"); }); $.ajax(“test.html”).then( function() { alert("哈哈,成功了!"); }, function() { alert("出错啦!"); }) OR
var 异步函数改造 = { } 一个异步函数需要经过改造才能使用 PROMISE/A编程模式 function wait() {
setTimeout(function() { alert(‘hello’); }, 2000) }
var 异步函数改造 = { } 把一个普通异步执行的函数改造成一个 deferred对象函数 function wait() {
setTimeout(function() { alert(‘hello’); }, 2000) } function wait() { var defer = $.Deferred(); setTimeout(function() { alert(‘hello’); defer.reslove(); }, 2000) return defer.promise(); }
var 异步函数改造 = { } 经过改造后的函数我们就可以这样使用了 wait().then(succFn, failFn, progssFn).then(…) 或者
$.Deferred(wait).then(succFn, failFn, progssFn).then(…)
var $.Deferred = { } • deferred.promise() • deferred.resolve() •
deferred.reject()
var PROMISE/A简单实现 = { } • 只对函数执行完成状态做处理 • 提供简单的promise().then(fn).then(fn)调用 Let’s
coding !
var defer = function() { var callback; return { resolve:
function(val) { var value = parsePms(val); callback && value.then(callback) }, promise: { then: function(fn) { var d = defer(); callback = function(val) { d.resolve(fn(val)); } return d.promise; } } } }
var parsePms = function (value) { if (value && typeof
value.then === "function") { return value; } else { return { then: function (callback) { return parsePms(callback(value)); } } } }
var PROMISE/A简单实现 = { } var log = function(a) {
var d = defer(); setTimeout(function() { console.log(a); d.resolve(++a); }, 1000) return d.promise; } log(1).then(log).then(log).then(log); Usage:
var PROMISE/A扩展 = { } when() alway() all() or() wait()
delay() next() More and more…
var 二次编译重口味优化 = { } 无论消息驱动还是PROMISE/A都不能摆脱显 式的对回调的依赖 有没有真正的异步同步化(同步编写,异步 执行)
var 二次编译重口味优化 = { } 无论消息驱动还是PROMISE/A都不能摆脱显 式的对回调的依赖 有没有真正的异步同步化(同步编写,异步 执行) Wind.js
(原名Jscex)
var Wind.js = { } Wind.js is an advanced library
which enable us to control flow with plain JavaScript for asynchronous programming (and more) without additional pre-compiling steps.
var Wind.js小例子 = { } var printAsync = eval(Wind.compile("async", function
(text) { $await(Wind.Async.sleep(1000)); console.log(text); })); var task = printAsync("Hello World"); tack.start(); 1s后控制台打印出信息
var Wind.js = { } 使用eval对定义的异步函数做二次编译 用setTimeout来模拟实现$wait()的阻塞等待 真正做到了同步编写异步执行
var Wind.js = { } Wind.js的确十分强大,也确实从解决实际问题出发的 But 曲高和寡,真正在项目中使用的并不多,许多jser也 并不接受
var Wind.js = { } Wind。Js之我见: 1. 依赖eval(eval is evil让大多数人望而却步,
即便老赵跟着别人屁股后面喊...) 2. 缺少文档 3. 二次编译调试的复杂性(有还是没有啊?)
var Wind.js = { } Wind。Js之我见: Wind.js是一个创新性和实用性兼具的 优秀JS库,能够很大程度解决异步流程 混乱问题,如果你的项目逻辑复杂需 要解决,为什么不用呢?
var 对比 = { } 1. 消息触发: 简单,回调的近亲,猜中开头, 也要猜中结尾 2.
PROMISE/A: 接口统一友好,理解难了点 3. 二次编译wind.js 最靠近同步编写异步执行的style, 适应性较难,需要换换口味
var 对比 = { } 其实我个人很推荐第二种方案 PROMISE/A的实践 一些你可能用得上promise的地方
var PROMISE/A实践 = { } 动画: animate1().then(animate2).then(animate3); 为什么非要这样? animate1(function() {
animate2(function() { animate3(); }) })
var PROMISE/A实践 = { } 对话框: $.dialog(‘hello’).done(fn).cancel(fn) 为什么一定要设计成 $.dialog({ ok:
function() {}, cancel: function() {} })
var PROMISE/A实践 = { } 对话框: $.dialog(‘hello’).done(fn).cancel(fn) 为什么一定要设计成 $.dialog({ ok:
function() {}, cancel: function() {} }) And more…
var 你怎么看 = { } 说到这里我想如果鄙视的眼神可以杀 人,我想我已经死了千百次了 大部分jser其实对异步编程回调嵌套的 问题不以为意
var 我为什么被鄙视 = { } 我们并不常写逻辑复杂,流程分支众 多等异步处理的代码,所以我们觉得 嵌套还OK 受禁锢的异步编程思维,大多数jser更 习惯并喜欢上旧有的函数回调模式。
嵌自己的套,让别人钻去吧
var open = { } 其实这是一个开放的话题,我们绝不是 要你做出某种选择,而放弃某种可能 我们所追求的是
var open = { } 其实这是一个开放的话题,我们绝不是 要你做出某种选择,而放弃某种可能 我们所追求的是 Happy coding
!
var javascript = { } 你有你的轻视,我有我的坚持;你可以说 你是程序员眼中的高富帅,但我却并不以 一个屌丝自居;你嘲笑我设计拙劣难成大 器,我可怜你固守自大满是吹嘘;但那又 怎样,哪怕被所有人误解,我也要勇敢的
做自己;我是javascript,我为自己代言。
Coding changes the world !!!
Thank you!!!