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
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
7
630
KATA
mclloyd
29
14k
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
30
4.6k
Reflections from 52 weeks, 52 projects
jeffersonlam
348
20k
Rebuilding a faster, lazier Slack
samanthasiow
80
8.8k
Making Projects Easy
brettharned
116
6k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
3
320
Unsuck your backbone
ammeep
669
57k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.8k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
666
120k
Fireside Chat
paigeccino
34
3.2k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
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!!!