JavaScript异步回调的Promise模式封装实例


Posted in Javascript onJune 07, 2014

网页的交互越来越复杂,JavaScript 的异步操作也随之越来越多。如常见的 ajax 请求,需要在请求完成时响应操作,请求通常是异步的,请求的过程中用户还能进行其他的操作,不会对页面进行阻塞,这种异步的交互效果对用户来说是挺有友好的。但是对于开发者来说,要大量处理这种操作,就很不友好了。异步请求完成的操作必须预先定义在回调函数中,等到请求完成就必须调用这个函数。这种非线性的异步编程方式会让开发者很不适应,同时也带来了诸多的不便,增加了代码的耦合度和复杂性,代码的组织上也会很不优雅,大大降低了代码的可维护性。情况再复杂点,如果一个操作要等到多个异步 ajax 请求的完成才能进行,就会出现回调函数嵌套的情况,如果需要嵌套好几层,那你就只能自求多福了。
先看看下面这个常见的异步函数。

var showMsg = function(){
    setTimeout(function(){
        alert( 'hello' );
    }, 5000 );
};

如果要给该函数添加回调,通常会这么干。

var showMsg = function( callback ){
    setTimeout(function(){
        alert( 'hello' );
        // 此处添加回调
        callback();
    }, 5000 );
};

如果是使用 easy.js 的 Promise,添加回调的方法就会优雅多了,前提是需要将原函数封装成一个 promise 实例。

var showMsg = function(){
    // 构造promise实例
    var promise = new E.Promise();    setTimeout(function(){
        alert( 'hello' );
        // 改变promise的状态
        promise.resolve( 'done' );
    }, 5000 );
    // 返回promise实例
    return promise;
};

将一个普通的函数封装成一个 promise 实例,有3个关键步骤,第一步是在函数内部构造一个 promise 实例,第二步是部署函数执行完去改变 promise 的状态为已完成,第三步就是返回这个 promise 实例。每个 promise 实例都有3种状态,分别为 pending(未完成)、resolved(已完成,成功)、rejected(已拒绝,失败)。下面再来看看如何添加回调。

showMsg().then(function( str ){
    // 回调添加到这里来了
    callback( str );
});

这样就将回调函数和原来的异步函数彻底的分离了,从代码组织上看,优雅了很多。resolve 接受一个参数,该参数就可以轻松实现将数据传送给使用 then 方法添加的回调中。
对于 ajax 请求,easy.js 直接将 ajax 方法封装成了 promise 对象,可以直接添加 then 方法来回调。

E.ajax({
    url : 'test1.php',
    type : 'GET'
})
.then(function(){
    // 添加请求成功的回调
}, function(){
    // 添加请求失败的回调
});

then 方法接受2个函数作为参数,第一个函数是已完成的回调,第二个就是已失败的回调。
如果有上面提到的多个 ajax 请求的情况呢?那么就要用到 when 这个方法了。该方法可以接受多个 promise 实例作为参数。

var requests = E.when(E.ajax({
    url : 'test1.php',
    type : 'GET'
}), E.ajax({
    url : 'test2.php',
    type : 'GET'
}));
requests.then(function( arg1, arg2 ){
    console.log( 'success:' + arg1[0] + arg2[0] );
}, function( arg1, arg2 ){
    console.log( 'failure:' + arg1 + arg2  );
});

when 方法是将多个 promise 实例存到一个数组中,等到该数组的所有 promise 实例都是已完成状态才去执行已完成的回调,一旦有一个实例是已拒绝的状态,则立即执行已拒绝的回调。

Promise 模式是 CommonJS 的规范之一。很多主流的 JavaScript 库都有相应的实现,如 jQuery 和 Dojo 中,都有 Deferred 去实现这些功能。在这里还是要吐槽下 jQuery 的 Deferred,撇开其内部使用,这应该用户使用率最低的一个模块了,这和其较复杂的使用方式有一定的关系。

Javascript 相关文章推荐
禁止F5等快捷键的JS代码
Mar 06 Javascript
JavaScript 调试器简介
Feb 21 Javascript
JavaScript 动态生成方法的例子
Jul 22 Javascript
图像替换新技术 状态域方法
Jan 28 Javascript
jquery中focus()函数实现当对象获得焦点后自动把光标移到内容最后
Sep 29 Javascript
DOM节点深度克隆函数cloneNode()用法实例
Jan 12 Javascript
ECMAScript 5中的属性描述符详解
Mar 02 Javascript
Javascript获取图片原始宽度和高度的方法详解
Sep 20 Javascript
javascript DOM的详解及实例代码
Mar 06 Javascript
AngularJS中$http使用的简单介绍
Mar 17 Javascript
JavaScript中闭包的详解
Apr 01 Javascript
Promise扫盲贴
Jun 24 Javascript
jQuery的缓存机制浅析
Jun 07 #Javascript
Firefox中使用outerHTML的2种解决方法
Jun 07 #Javascript
jQuery 顶部导航跟随滚动条滚动固定浮动在顶部
Jun 06 #Javascript
判断iframe里的页面是否加载完成
Jun 06 #Javascript
javascript获取隐藏元素(display:none)的高度和宽度的方法
Jun 06 #Javascript
js中的hasOwnProperty和isPrototypeOf方法使用实例
Jun 06 #Javascript
jquery数组过滤筛选方法grep()简介
Jun 06 #Javascript
You might like
ThinkPHP水印功能实现修复PNG透明水印并增加JPEG图片质量可调整
2014/11/05 PHP
详解在PHP的Yii框架中使用行为Behaviors的方法
2016/03/18 PHP
PHP实现的最大正向匹配算法示例
2017/12/19 PHP
PHP操作路由器实现方法示例
2019/04/27 PHP
laravel框架邮箱认证实现方法详解
2019/11/22 PHP
javascript Prototype 对象扩展
2009/05/15 Javascript
深入理解JavaScript系列(8) S.O.L.I.D五大原则之里氏替换原则LSP
2012/01/15 Javascript
在ASP.NET中使用JavaScript脚本的方法
2013/11/12 Javascript
简介JavaScript中toUpperCase()方法的使用
2015/06/06 Javascript
Javascript 函数的四种调用模式
2016/11/05 Javascript
详解jQuery中的DOM操作
2016/12/23 Javascript
详解基于Bootstrap+angular的一个豆瓣电影app
2017/06/26 Javascript
如何从零开始手写Koa2框架
2019/03/22 Javascript
Node.js API详解之 vm模块用法实例分析
2020/05/27 Javascript
vue-cli4.x创建企业级项目的方法步骤
2020/06/18 Javascript
[04:22]DOTA2大事件之护国神翼
2020/08/14 DOTA
Python HTMLParser模块解析html获取url实例
2015/04/08 Python
使用Python生成随机密码的示例分享
2016/02/18 Python
Python3 Random模块代码详解
2017/12/04 Python
酷! 程序员用Python带你玩转冲顶大会
2018/01/17 Python
python如何让类支持比较运算
2018/03/20 Python
基于windows下pip安装python模块时报错总结
2018/06/12 Python
获取django框架orm query执行的sql语句实现方法分析
2019/06/20 Python
python匿名函数的使用方法解析
2019/10/10 Python
Python基于os.environ从windows获取环境变量
2020/06/09 Python
给Django Admin添加验证码和多次登录尝试限制的实现
2020/07/26 Python
css3媒体查询中device-width和width的区别详解
2020/03/27 HTML / CSS
德国排名第一的主题公园门票网站:Attraction Tickets Direct
2019/09/09 全球购物
马来西亚网上花店:FlowerAdvisor马来西亚
2020/01/03 全球购物
武汉世纪畅想数字传播有限公司.NET笔试题
2014/07/22 面试题
小学教师自我鉴定
2013/11/07 职场文书
群教班子对照检查材料
2014/08/26 职场文书
群众路线个人剖析材料及整改措施
2014/11/04 职场文书
婚礼庆典答谢词
2015/01/20 职场文书
国情备忘录观后感
2015/06/04 职场文书
代码复现python目标检测yolo3详解预测
2022/05/06 Python