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查看html源文件
Nov 08 Javascript
js字符编码函数区别分析
Jun 05 Javascript
一个用javascript写的select支持上下键、首字母筛选以及回车取值的功能
Sep 09 Javascript
js DOM 元素ID就是全局变量
Sep 20 Javascript
javascript跑马灯悬停放大效果实现代码
Dec 12 Javascript
JavaScript表达式:URL 协议介绍
Mar 10 Javascript
js获取当前时间显示在页面上并每秒刷新
Dec 24 Javascript
jQuery实现的登录浮动框效果代码
Sep 26 Javascript
gulp解决跨域的配置文件问题
Jun 08 Javascript
详解基于Vue的支持数据双向绑定的select组件
Sep 02 Javascript
关于Vue中axios的封装实例详解
Oct 20 Javascript
JavaScript实现公告栏上下滚动效果
Mar 13 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 遍历显示文件夹下所有目录、所有文件的函数,没有分页的代码
2008/11/14 PHP
php URL验证正则表达式
2011/07/19 PHP
PHP判断浏览器、判断语言代码分享
2015/03/05 PHP
Microsfot .NET Framework4.0框架 安装失败的解决方法
2013/08/14 Javascript
JavaScript的事件代理和委托实例分析
2015/03/25 Javascript
禁止按回车键提交表单的方法
2015/06/11 Javascript
js实现仿阿里巴巴城市选择框效果实例
2015/06/24 Javascript
js+css3实现旋转效果
2017/01/20 Javascript
详解nodejs中express搭建权限管理系统
2017/09/15 NodeJs
vue用addRoutes实现动态路由的示例
2017/09/15 Javascript
使用sessionStorage解决vuex在页面刷新后数据被清除的问题
2018/04/13 Javascript
js与jQuery实现获取table中的数据并拼成json字符串操作示例
2018/07/12 jQuery
详解vue.js下引入百度地图jsApi的两种方法
2018/07/27 Javascript
基于Node.js搭建hexo博客过程详解
2019/06/25 Javascript
vue+导航锚点联动-滚动监听和点击平滑滚动跳转实例
2019/11/13 Javascript
解决vant的Toast组件时提示not defined的问题
2020/11/11 Javascript
Python常用正则表达式符号浅析
2014/08/13 Python
python获取当前日期和时间的方法
2015/04/30 Python
python matplotlib 注释文本箭头简单代码示例
2018/01/08 Python
python将一组数分成每3个一组的实例
2018/11/14 Python
Python提取频域特征知识点浅析
2019/03/04 Python
Python在Matplotlib图中显示中文字体的操作方法
2019/07/29 Python
Django项目后台不挂断运行的方法
2019/08/31 Python
python中树与树的表示知识点总结
2019/09/14 Python
PyQt5多线程刷新界面防假死示例
2019/12/13 Python
利用OpenCV中对图像数据进行64F和8U转换的方式
2020/06/03 Python
Python如何读取、写入JSON数据
2020/07/28 Python
sublime3之内网安装python插件Anaconda的流程
2020/11/10 Python
eharmony澳大利亚:网上约会服务
2020/02/29 全球购物
培训主管的岗位职责
2013/11/23 职场文书
生产文员岗位职责
2014/04/05 职场文书
中国梦演讲稿3分钟
2014/08/19 职场文书
自我评价优缺点范文
2015/03/11 职场文书
村级干部党员公开承诺事项
2015/05/04 职场文书
《烈火英雄》观后感:致敬和平时代的英雄
2019/11/11 职场文书
引用计数法和root搜索算法以及JVM中判定对象需要回收的方法
2022/04/19 Java/Android