Slide 1

Slide 1 text

JavaScript 异步编程探索 var KEYWORDs = { author: “李诚”, } date: “2013/3/18”, alias: “使用消息触发、Promise/A、二次编译提升异步编程体验” , E-mail: “chen.ican@gmail.com”

Slide 2

Slide 2 text

var 目录 = { } • javascript异步编程简介 • javascript异步编程优化:  消息触发  Promise/A  二次编译 • 分析总结

Slide 3

Slide 3 text

var 预期 = { } • 了解JS中异步回调引发的问题 • 理解针对该问题提出的三种优化方案 • 在实际编程过程中,在某些具体情况 下引入某种解决方案 • Open our mind

Slide 4

Slide 4 text

var JS异步编程简介 = { } 1. 异步和同步之别 2. JS异步的必要性 3. 异步导致的问题

Slide 5

Slide 5 text

var 同步和异步 = { } 异步:任务分割 同步:顺序执行,等待,阻塞

Slide 6

Slide 6 text

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; }

Slide 7

Slide 7 text

var JS异步执行的操作 = { } • Ajax(XMLHttpRequest) • setTimeout/setInterval • CSS3 Transition/Animation • postMessage • Web Workers • Web Sockets • and more… 所有耗时的操作都应进行分解异步执行

Slide 8

Slide 8 text

var JS异步操作的必要性 = { } 原因:单线程(?) ->排队模式->事件队列 必要性: 防止阻塞: UI更新、事件监听、用户操作 异步重要武器:回调函数

Slide 9

Slide 9 text

var JS回调函数 = { } 异步编程条件下控制程序的执行流程 回调是JS异步编程模式下能够顺利进 行的必要条件

Slide 10

Slide 10 text

var JS回调函数 = { } 把函数当多参数传递,并在另一个 函数中执行传递进来的函数 var fn = function(fn1, fn2, fn3) { fn1(); fn2(); fn3(); }

Slide 11

Slide 11 text

var JS回调函数 = { } 把函数当多参数传递,并在另一个 函数中执行传递进来的函数 var fn = function(fn1, fn2, fn3) { fn1(); fn2(); fn3(); }

Slide 12

Slide 12 text

var JS异步编程的问题 = { } 保证A、B、C、D、E方法顺序执行 同步执行时: A(); B(); C(); D(); E(); 异步时: A(function() { B(function() { C(function() { D(function() { E(); }); }); }); });

Slide 13

Slide 13 text

var JS异步编程的问题 = { } 来自 https://github.com/christkv/node-mongodb-native/blob/master/examples/blog.js 爱上嵌套需要很 多年,讨厌嵌套 只需要一段这样 的代码…… 感觉不会再爱了

Slide 14

Slide 14 text

var JS异步编程的问题 = { } 这个世界上不存在所谓回调函数深度嵌套的问题。 —— Jackson Tian 世界上本没有嵌套回调,写得人多了,也便有了}}}}}}}}}}}}。 —— fengmk2 所有回调函数深度嵌套的行为都是耍流氓。

Slide 15

Slide 15 text

var JS异步编程的问题 = { } • 代码结构支离破碎 • 可读性降低,提高的代码的复杂度 • 对回调的严重依赖 • 非线性的适应

Slide 16

Slide 16 text

var JS异步编程的问题 = { } • 代码结构支离破碎 • 可读性降低,提高的代码的复杂度 • 对回调的严重依赖 • 非线性的适应 流程混乱、编程体验糟糕

Slide 17

Slide 17 text

var JS异步编程优化方案 = { } 1.消息触发 2.PROMISE/A 3.二次编译

Slide 18

Slide 18 text

var JS异步编程优化 = { } 消息触发: 将函数依赖关系先进行声明,并在函数执行完 毕时发出执行完毕的消息,如果依赖函数都发 出执行完毕的消息,则该依赖函数开始执行 代表:EventProxy.js

Slide 19

Slide 19 text

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' ); });

Slide 20

Slide 20 text

var 消息触发 = { } 优点:实现简单,较易理解,并有效解决 了某些时候函数深度嵌套的问题,同时能 降低代码的耦合度 缺点:需要显式的书写函数依赖声明代码

Slide 21

Slide 21 text

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规范

Slide 22

Slide 22 text

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)

Slide 23

Slide 23 text

var Promise/A参数传递 = { } • resolve(param) -> fulfilledHandler(param) • reject(param) -> errorHandler(param) 通过promise的resolve和reject方法来向后 传递参数

Slide 24

Slide 24 text

var jQuery deferred = { } $.Deferred: Jquery 1.5版本基于Promise/A规范实现 应用: $.ajax返回对象的变更: <1.5:$.ajax方法返回XHR对象 >=1.5:$.ajax返回$.deferred对象

Slide 25

Slide 25 text

var $.Deferred使用示例 = { } 普通青年一般都这样写Ajax请求: $.ajax({ url: "test.html", success: function() { alert("哈哈,成功了!"); }, error: function() { alert("出错啦!"); } });

Slide 26

Slide 26 text

var $.Deferred使用示例 = { } 普通青年一般都这样写Ajax请求: $.ajax({ url: "test.html", success: function() { alert("哈哈,成功了!"); }, error: function() { alert("出错啦!"); } });

Slide 27

Slide 27 text

var $.Deferred使用示例 = { } $.ajax("test.html") .done(function() { alert("哈哈,成功了!"); }) .fail(function() { alert("出错啦!"); }); $.ajax(“test.html”).then( function() { alert("哈哈,成功了!"); }, function() { alert("出错啦!"); }) OR

Slide 28

Slide 28 text

var 异步函数改造 = { } 一个异步函数需要经过改造才能使用 PROMISE/A编程模式 function wait() { setTimeout(function() { alert(‘hello’); }, 2000) }

Slide 29

Slide 29 text

var 异步函数改造 = { } 把一个普通异步执行的函数改造成一个 deferred对象函数 function wait() { setTimeout(function() { alert(‘hello’); }, 2000) } function wait() { var defer = $.Deferred(); setTimeout(function() { alert(‘hello’); defer.reslove(); }, 2000) return defer.promise(); }

Slide 30

Slide 30 text

var 异步函数改造 = { } 经过改造后的函数我们就可以这样使用了 wait().then(succFn, failFn, progssFn).then(…) 或者 $.Deferred(wait).then(succFn, failFn, progssFn).then(…)

Slide 31

Slide 31 text

var $.Deferred = { } • deferred.promise() • deferred.resolve() • deferred.reject()

Slide 32

Slide 32 text

var PROMISE/A简单实现 = { } • 只对函数执行完成状态做处理 • 提供简单的promise().then(fn).then(fn)调用 Let’s coding !

Slide 33

Slide 33 text

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; } } } }

Slide 34

Slide 34 text

var parsePms = function (value) { if (value && typeof value.then === "function") { return value; } else { return { then: function (callback) { return parsePms(callback(value)); } } } }

Slide 35

Slide 35 text

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:

Slide 36

Slide 36 text

var PROMISE/A扩展 = { } when() alway() all() or() wait() delay() next() More and more…

Slide 37

Slide 37 text

var 二次编译重口味优化 = { } 无论消息驱动还是PROMISE/A都不能摆脱显 式的对回调的依赖 有没有真正的异步同步化(同步编写,异步 执行)

Slide 38

Slide 38 text

var 二次编译重口味优化 = { } 无论消息驱动还是PROMISE/A都不能摆脱显 式的对回调的依赖 有没有真正的异步同步化(同步编写,异步 执行) Wind.js (原名Jscex)

Slide 39

Slide 39 text

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.

Slide 40

Slide 40 text

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后控制台打印出信息

Slide 41

Slide 41 text

var Wind.js = { } 使用eval对定义的异步函数做二次编译 用setTimeout来模拟实现$wait()的阻塞等待 真正做到了同步编写异步执行

Slide 42

Slide 42 text

var Wind.js = { } Wind.js的确十分强大,也确实从解决实际问题出发的 But 曲高和寡,真正在项目中使用的并不多,许多jser也 并不接受

Slide 43

Slide 43 text

var Wind.js = { } Wind。Js之我见: 1. 依赖eval(eval is evil让大多数人望而却步, 即便老赵跟着别人屁股后面喊...) 2. 缺少文档 3. 二次编译调试的复杂性(有还是没有啊?)

Slide 44

Slide 44 text

var Wind.js = { } Wind。Js之我见: Wind.js是一个创新性和实用性兼具的 优秀JS库,能够很大程度解决异步流程 混乱问题,如果你的项目逻辑复杂需 要解决,为什么不用呢?

Slide 45

Slide 45 text

var 对比 = { } 1. 消息触发: 简单,回调的近亲,猜中开头, 也要猜中结尾 2. PROMISE/A: 接口统一友好,理解难了点 3. 二次编译wind.js 最靠近同步编写异步执行的style, 适应性较难,需要换换口味

Slide 46

Slide 46 text

var 对比 = { } 其实我个人很推荐第二种方案 PROMISE/A的实践 一些你可能用得上promise的地方

Slide 47

Slide 47 text

var PROMISE/A实践 = { } 动画: animate1().then(animate2).then(animate3); 为什么非要这样? animate1(function() { animate2(function() { animate3(); }) })

Slide 48

Slide 48 text

var PROMISE/A实践 = { } 对话框: $.dialog(‘hello’).done(fn).cancel(fn) 为什么一定要设计成 $.dialog({ ok: function() {}, cancel: function() {} })

Slide 49

Slide 49 text

var PROMISE/A实践 = { } 对话框: $.dialog(‘hello’).done(fn).cancel(fn) 为什么一定要设计成 $.dialog({ ok: function() {}, cancel: function() {} }) And more…

Slide 50

Slide 50 text

var 你怎么看 = { } 说到这里我想如果鄙视的眼神可以杀 人,我想我已经死了千百次了 大部分jser其实对异步编程回调嵌套的 问题不以为意

Slide 51

Slide 51 text

var 我为什么被鄙视 = { } 我们并不常写逻辑复杂,流程分支众 多等异步处理的代码,所以我们觉得 嵌套还OK 受禁锢的异步编程思维,大多数jser更 习惯并喜欢上旧有的函数回调模式。 嵌自己的套,让别人钻去吧

Slide 52

Slide 52 text

var open = { } 其实这是一个开放的话题,我们绝不是 要你做出某种选择,而放弃某种可能 我们所追求的是

Slide 53

Slide 53 text

var open = { } 其实这是一个开放的话题,我们绝不是 要你做出某种选择,而放弃某种可能 我们所追求的是 Happy coding !

Slide 54

Slide 54 text

var javascript = { } 你有你的轻视,我有我的坚持;你可以说 你是程序员眼中的高富帅,但我却并不以 一个屌丝自居;你嘲笑我设计拙劣难成大 器,我可怜你固守自大满是吹嘘;但那又 怎样,哪怕被所有人误解,我也要勇敢的 做自己;我是javascript,我为自己代言。

Slide 55

Slide 55 text

Coding changes the world !!!

Slide 56

Slide 56 text

Thank you!!!