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 相关文章推荐
JavaScript 原型链学习总结
Oct 29 Javascript
JavaScript中数组对象的那些自带方法介绍
Mar 12 Javascript
js Map List 遍历使用示例
Jul 10 Javascript
js中iframe调用父页面的方法
Oct 30 Javascript
AngularJS基础学习笔记之控制器
May 10 Javascript
jQuery插件之jQuery.Form.js用法实例分析(附demo示例源码)
Jan 04 Javascript
jquery获取复选框checkbox的值实现方法
May 30 Javascript
原生JS与jQuery编写简单选项卡
Oct 30 jQuery
Vue CLI3搭建的项目中路径相关问题的解决
Sep 17 Javascript
vue组件数据传递、父子组件数据获取,slot,router路由功能示例
Mar 19 Javascript
关于vue2强制刷新,解决页面不会重新渲染的问题
Oct 29 Javascript
vue解决跨域问题(推荐)
Nov 10 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
DC《小丑》11项提名领跑奥斯卡 Netflix成第92届奥斯卡提名最大赢家
2020/04/09 欧美动漫
PHP中使用FFMPEG获取视频缩略图和视频总时长实例
2014/05/04 PHP
ThinkPHP访问不存在的模块跳转到404页面的方法
2014/06/19 PHP
PHP 实现类似js中alert() 提示框
2015/03/18 PHP
PHP实现的基于单向链表解决约瑟夫环问题示例
2017/09/30 PHP
PHP+AJAX 投票器功能
2017/11/11 PHP
javascript 鼠标滚轮事件
2009/04/09 Javascript
自定义jQuery插件方式实现强制对象重绘的方法
2015/03/23 Javascript
JavaScript框架是什么?怎样才能叫做框架?
2015/07/01 Javascript
浅析JavaScript访问对象属性和方法及区别
2015/11/16 Javascript
纯JS代码实现气泡效果
2016/05/04 Javascript
原生js实现jquery函数animate()动画效果的简单实例
2016/08/21 Javascript
jQuery实现弹幕效果
2017/02/17 Javascript
微信小程序实现点击按钮移动view标签的位置功能示例【附demo源码下载】
2017/12/06 Javascript
详解webpack-dev-server的简单使用
2018/04/02 Javascript
Node.js引入UIBootstrap的方法示例
2018/05/11 Javascript
微信小程序动态添加view组件的实例代码
2019/05/23 Javascript
通过微信公众平台获取公众号文章的方法示例
2019/12/25 Javascript
javascript 数组精简技巧小结
2020/02/26 Javascript
[38:23]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第一场
2014/05/24 DOTA
[03:05]《我与DAC》之xiao8:DAC与BG
2018/03/27 DOTA
Python中装饰器的一个妙用
2015/02/08 Python
python实现基于两张图片生成圆角图标效果的方法
2015/03/26 Python
Python将多个excel文件合并为一个文件
2018/01/03 Python
浅谈pandas用groupby后对层级索引levels的处理方法
2018/11/06 Python
使用celery执行Django串行异步任务的方法步骤
2019/06/06 Python
Python基于gevent实现高并发代码实例
2020/05/15 Python
h5实现获取用户地理定位的实例代码
2017/07/17 HTML / CSS
阳光体育:Sunny Sports(购买露营和远足设备)
2018/08/07 全球购物
网站域名和主机:Domain.com
2019/04/01 全球购物
物流经理自我评价
2013/09/23 职场文书
《中国的气候》教学反思
2014/02/23 职场文书
初中班主任寄语
2014/04/04 职场文书
2015元旦节寄语
2014/12/08 职场文书
在校生证明
2015/06/17 职场文书
GPU服务器的多用户配置方法
2022/07/07 Servers