Promises与Javascript异步编程
Promises与Javascript异步编程
转载:http://www.zawaliang.com/2013/08/399.html
在如今都追求用户体验的时代,Ajax应用真的是无所不在。加上这些年浏览器技术、HTML5以及CSS3等的发展,越来越多的富Web应用出现;在给与我们良好体验的同时,Web开发人员在背后需要处理越来越多的异步回调逻辑。
笔者对最近读完的《Async Javascript-Build More Responsive Apps with Less Code》(Javascript异步编程-设计快速响应的网络应用)一书以及部分资料,整理了我认为比较重要的一些点以及容易理解错的地方,使大家对 Promise对象以及异步编程有更深的认识。
嵌套式回调
setTimeout(function() {
setTimeout(function() {
// do something
}, 10)
}, 100);
$.ajax(url, function() {
$.ajax(url2, function() {
$.ajax(url3, function() {
// do something
});
});
});
可是问题来了,当我们的嵌套越多,代码结构层级会变得越来越深。首先是阅读上会变得困难;其次是强耦合,接口变得不好扩展。我们需要一种模式来解决这种问题,这就是Promises所要做的事情。
异步函数类型
Javascript里异步函数可以分为两大类型:
- I/O函数(Ajax、script…)
- 计时函数(setTimeout、setInterval、setImmediate)
异步函数异常捕获
try {
setTimeout(function A() {
setTimeout(function B() {
setTimeout(function C() {
throw new Error('Error');
}, 0);
}, 0);
}, 0);
} catch (e) {}
运行以上代码,A、B、C被添加到事件队列里;异常触发时,A、B已被移出事件队列,内存堆栈里只存在C,此时的异常不被try捕获,只会流向应用程序未捕获异常处理器。
所以,在异步函数里,不能使用try/catch捕获异常。
分布式事件
Javascript的事件核心是事件分发机制,通过对发布者绑定订阅句柄来达到异步相响应的目的:
document.onclick = function() {
// click
};
PubSub(Publish/Subscribe, 发布/订阅)模式,就是这么一种模式,通过订阅发布者的事件响应来达到多层分发解耦的目的。
以下是一个简单版本的PubSub模式实现:
var PubSub = (function() {
var _handlers = {};
return {
// 订阅事件
on: function(eventType, handler) {
if (!_handlers[eventType]) {
_handlers[eventType] = [];
}
if (typeof handler == 'function') {
_handlers[eventType].push(handler);
}
},
//发布事件
emit: function(eventType) {
var args = Array.prototype.slice.call(arguments, 1);
var handlers = _handlers[eventType] || [];
for (var i = 0, len = handlers.length; i < len; i++) {
handlers[i].apply(null, args)
}
}
};
})();
Promises/A规范
CommonJS之Promises/A规范是Kris Zyp于2009年提出来的,它通过规范API接口来简化异步编程,使我们的异步逻辑代码更易理解。
遵循Promises/A规范的实现我们称之为Promise对象,Promise对象有且仅有三种状态:unfulfilled(未完成)、 fulfilled(已完成)、failed(失败/拒绝);而且状态变化只能从unfulfilled到fulfilled,或者 unfulfilled到failed;
Promise对象需实现一个then接口,then(fulfilledHandler, errorHandler, progressHandler);then接口接收一个成功回调(fulfilledHandler)与一个失败回调(errorHandler);progressHandler触发回调是可选的,Promise对象没有强制去回调此句柄。
then方法的实现需要返回一个新的Promise对象,以形成链式调用,或者叫Promise管道。
为了实现状态的转变,我们还需要实现另外两个接口:
- resolve:实现状态由未完成到已完成
- reject:实现状态由未完成到拒绝(失败)
这样子我们开篇所说的嵌套式回调就可以这样子写了:
// 这里假设Promise是一个已实现的Promise对象
function asyncFn1() {
var p = new Promise();
setTimeout(function() {
console.log(1);
p.resolve(); // 标记为已完成
}, 2000);
return p;
}
function asyncFn2() {
var p = new Promise();
setTimeout(function() {
console.log(2);
p.reject('error'); // 标记为拒绝
}, 1000);
return p;
}
asyncFn1()
.then(function() {
return asyncFn2();
}).then(function() {
console.log('done');
}, function(err) {
console.log(err);
});
有了Promise,我们可以以同步的思维去编写异步的逻辑了。在同步函数的世界里,有2个非常重要的概念:
有返回值
可以抛出异常
Promise不仅仅是一种可以链式调用的对象,更深层次里,它为异步函数与同步函数提供了一种更加直接的对应关系。
上面我们说过,在异步函数里,不能使用try/catch捕获异常,因此也不能抛出异常。有了Promise,只要我们显式定义了errorHandler,那么我们就可以做到像同步函数那样的异常捕获了。
转载:http://www.zawaliang.com/2013/08/399.html
Promises与Javascript异步编程的更多相关文章
- 转: Promises与Javascript异步编程
在如今都追求用户体验的时代,Ajax应用真的是无所不在.加上这些年浏览器技术.HTML5以及CSS3等的发展,越来越多的富Web应用出现:在给与我们良好体验的同时,Web开发人员在背后需要处理越来越多 ...
- JavaScript异步编程原理
众所周知,JavaScript 的执行环境是单线程的,所谓的单线程就是一次只能完成一个任务,其任务的调度方式就是排队,这就和火车站洗手间门口的等待一样,前面的那个人没有搞定,你就只能站在后面排队等着. ...
- 深入解析Javascript异步编程
这里深入探讨下Javascript的异步编程技术.(P.S. 本文较长,请准备好瓜子可乐 :D) 一. Javascript异步编程简介 至少在语言级别上,Javascript是单线程的,因此异步编程 ...
- 探索Javascript异步编程
异步编程带来的问题在客户端Javascript中并不明显,但随着服务器端Javascript越来越广的被使用,大量的异步IO操作使得该问题变得明显.许多不同的方法都可以解决这个问题,本文讨论了一些方法 ...
- JavaScript异步编程的主要解决方案—对不起,我和你不在同一个频率上
众所周知(这也忒夸张了吧?),Javascript通过事件驱动机制,在单线程模型下,以异步的形式来实现非阻塞的IO操作.这种模式使得JavaScript在处理事务时非常高效,但这带来了很多问题,比如异 ...
- javascript异步编程的前世今生,从onclick到await/async
javascript与异步编程 为了避免资源管理等复杂性的问题, javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是为 ...
- JavaScript异步编程(2)- 先驱者:jsDeferred
JavaScript当前有众多实现异步编程的方式,最为耀眼的就是ECMAScript 6规范中的Promise对象,它来自于CommonJS小组的努力:Promise/A+规范. 研究javascri ...
- 5分种让你了解javascript异步编程的前世今生,从onclick到await/async
javascript与异步编程 为了避免资源管理等复杂性的问题,javascript被设计为单线程的语言,即使有了html5 worker,也不能直接访问dom. javascript 设计之初是 ...
- JavaScript异步编程
前言 如果你有志于成为一个优秀的前端工程师,或是想要深入学习JavaScript,异步编程是必不可少的一个知识点,这也是区分初级,中级或高级前端的依据之一.如果你对异步编程没有太清晰的概念,那么我建议 ...
随机推荐
- mariadb介绍
事务(Transaction):组织多个操作为一个整体,要么全部执行,要么全部不执行 “回滚” ,rollback SQL接口:sql语句分析器和优化器 表:为了满足范式设计要求,将一个数据集分拆为多 ...
- php设计模式之Proxy(代理模式)和Facade(外观)设计模式
Proxy(代理模式)和Facade(外观)设计模式它们均为更复杂的功能提供抽象化的概念,但这两种实现抽象化的过程大不相同 Proxy案例中,所有的方法和成员变量都来自于目标对象,必要时,该代理能够对 ...
- firefox 扩展开发笔记(三):高级ui交互编程
firefox 扩展开发笔记(三):高级ui交互编程 前言 前两篇链接 1:firefox 扩展开发笔记(一):jpm 使用实践以及调试 2:firefox 扩展开发笔记(二):进阶开发之移动设备模拟 ...
- linux内核SPI总线驱动分析(一)(转)
linux内核SPI总线驱动分析(一)(转) 下面有两个大的模块: 一个是SPI总线驱动的分析 (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) ...
- PHP 学习笔记 01
例子: 为什么要学PHP 主观原因: 前段时间在学校处理了毕业的一些事情,回到上海后开始了找工作的旅程.意向工作是WPF开发或者ASP.NET 作为后端的WEB开发. 陆陆续续一直在面试,其中有一家公 ...
- EXCEL处理数据小技巧
1.EXCEL 中如何获得4*8这个数字中,*号前面的数字 输入 =LEFT(AC2,FIND("*",AC2)-1) 获得*右边的数字 输入 =RIGHT(AC2,FIND(& ...
- Boolean.parseBoolean("true") 和 Boolean.getBoolean("true");的区别及用法
正确用法:boolean repeatIndicator = Boolean.valueOf("true").booleanValue();或者也可以使用Boolean.parse ...
- OC开发中运用到的枚举
一 常见枚举的定义: typedef enum { LOGIN_SUCCESS, USER_NAME, USER_PASSWORD, OLD_LAT, OLD_LNG }FIELD_SAVED; ...
- Redis 客户端配置及示例
一.redis自定义配置节点 <configSections> <section name ="RedisConfig" type="Amy.Toolk ...
- 条款20:以const-reference传递替换by-value传递
缺省情况下,C++中函数参数的传递方式为by-value.即函数都是以实际参数的副本进行传递,而函数返回的也是一个副本.考虑如下实例程序: #include <iostream> clas ...