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 相关文章推荐
pjblog中的UBBCode.js
Apr 25 Javascript
JS批量操作CSS属性详细解析
Dec 16 Javascript
可自定义速度的js图片无缝滚动示例分享
Jan 20 Javascript
深入探究JavaScript中for循环的效率问题及相关优化
Mar 13 Javascript
JavaScript中关于for循环删除数组元素内容时出现的问题
Nov 21 Javascript
利用JS轻松实现获取表单数据
Dec 06 Javascript
Vue 指令实现按钮级别权限管理功能
Apr 23 Javascript
layerui代码控制tab选项卡,添加,关闭的实例
Sep 04 Javascript
layui复选框限制选择个数的方法
Sep 18 Javascript
浅谈JavaScript中你可能不知道URL构造函数的属性
Jul 13 Javascript
js实现纯前端压缩图片
Nov 16 Javascript
video.js添加自定义组件的方法
Dec 09 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
PHP strtotime函数详解
2009/12/18 PHP
PHP通过iconv将字符串从GBK转换为UTF8字符集
2011/07/18 PHP
深入理解PHP内核(二)之SAPI探究
2015/11/10 PHP
php好代码风格的阶段性总结
2016/06/25 PHP
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
jquery ready()的几种实现方法小结
2010/06/18 Javascript
silverlight线程与基于事件驱动javascript引擎(实现轨迹回放功能)
2011/08/09 Javascript
一些有用的JavaScript和jQuery的片段分享
2011/08/23 Javascript
表单提交前触发函数返回true表单才会提交
2014/03/11 Javascript
自己封装的javascript事件队列函数版
2014/06/12 Javascript
AngularJS快速入门
2015/04/02 Javascript
Bootstrap+jfinal实现省市级联下拉菜单
2016/05/30 Javascript
原生态js,鼠标按下后,经过了那些单元格的简单实例
2016/08/11 Javascript
全面解析vue router 基本使用(动态路由,嵌套路由)
2018/09/02 Javascript
vuejs2.0运用原生js实现简单拖拽元素功能
2020/08/21 Javascript
使用mixins实现elementUI表单全局验证的解决方法
2019/04/02 Javascript
vue实现树状表格效果
2020/12/29 Vue.js
[16:56]heroes英雄教学 司夜刺客
2014/09/18 DOTA
[04:45]上海特级锦标赛主赛事第三日TOP10
2016/03/05 DOTA
[35:29]Secret vs VG 2018国际邀请赛淘汰赛BO3 第三场 8.23
2018/08/24 DOTA
详解Django中的权限和组以及消息
2015/07/23 Python
Python模拟随机游走图形效果示例
2018/02/06 Python
python读取文本中数据并转化为DataFrame的实例
2018/04/10 Python
使用python读取txt文件的内容,并删除重复的行数方法
2018/04/18 Python
python中rb含义理解
2020/06/18 Python
H5页面适配iPhoneX(就是那么简单)
2019/12/02 HTML / CSS
Sneaker Studio法国:购买运动鞋
2018/06/08 全球购物
.net软件工程师应聘上机试题
2015/03/10 面试题
营销总经理岗位职责
2014/02/02 职场文书
2014年五四青年节活动策划书
2014/04/22 职场文书
个人委托函范文
2015/01/29 职场文书
中学生国庆节演讲稿2015
2015/07/30 职场文书
财务管理制度范本
2015/08/04 职场文书
大学生饮品店创业计划书范文
2019/07/10 职场文书
大学生军训心得体会5篇
2019/08/15 职场文书
Python 使用 Frame tkraise() 方法在 Tkinter 应用程序中的Frame之间切换
2022/04/24 Python