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 相关文章推荐
textContent在Firefox下与innerText等效的属性
May 12 Javascript
JQUERY设置IFRAME的SRC值的代码
Nov 30 Javascript
js 优化次数过多的循环 考虑到性能问题
Mar 05 Javascript
将字符串转换成gb2312或者utf-8编码的参数(js版)
Apr 10 Javascript
JSON+HTML实现国家省市联动选择效果
May 18 Javascript
基于OL2实现百度地图ABCD marker的效果
Oct 01 Javascript
jQuery遮罩层效果实例分析
Jan 14 Javascript
Three.js学习之正交投影照相机
Aug 01 Javascript
使用ajaxfileupload.js实现上传文件功能
Aug 13 Javascript
简单实现Bootstrap标签页
Aug 09 Javascript
js中数组插入、删除元素操作的方法
Feb 15 Javascript
taro小程序添加骨架屏的实现代码
Nov 15 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 使用MySQL管理Session的回调函数详解
2013/06/21 PHP
ThinkPHP之foreach标签使用概述
2014/06/30 PHP
实用的PHP带公钥加密类分享(每次加密结果都不一样哦)
2014/08/20 PHP
php源码分析之DZX1.5加密解密函数authcode用法
2015/06/17 PHP
php解决DOM乱码的方法示例代码
2016/11/20 PHP
PHP常用的三种设计模式
2017/02/17 PHP
PHP实现json_decode不转义中文的方法
2017/05/20 PHP
[企业公众号]升级到[企业微信]之后发送消息失败的解决方法
2017/06/30 PHP
yii2 url重写并隐藏index.php方法
2018/12/10 PHP
jq实现酷炫的鼠标经过图片翻滚效果
2014/03/12 Javascript
利用原生JavaScript获取元素样式只是获取而已
2014/10/08 Javascript
JS 新增Cookie 取cookie值 删除cookie 举例详解
2014/10/10 Javascript
javascript编程实现栈的方法详解【经典数据结构】
2017/04/11 Javascript
ES6扩展运算符用法实例分析
2017/10/31 Javascript
Vue的事件响应式进度条组件实例详解
2018/02/04 Javascript
JS遍历DOM文档树的方法实例详解
2018/04/03 Javascript
Vue开发之watch监听数组、对象、变量操作分析
2019/04/25 Javascript
解决Angularjs异步操作后台请求用$q.all排列先后顺序问题
2019/11/29 Javascript
node.js使用 http-proxy 创建代理服务器操作示例
2020/02/10 Javascript
vue 页面回退mounted函数不执行的解决方案
2020/07/26 Javascript
Vant Weapp组件踩坑:picker的初始赋值解决
2020/11/12 Javascript
Python有序字典简单实现方法示例
2017/09/28 Python
详解Python中的测试工具
2019/06/09 Python
python celery分布式任务队列的使用详解
2019/07/08 Python
检测python爬虫时是否代理ip伪装成功的方法
2019/07/12 Python
python rsync服务器之间文件夹同步脚本
2019/08/29 Python
Python Numpy中数据的常用保存与读取方法
2020/04/01 Python
html5使用canvas绘制一张图片
2014/12/15 HTML / CSS
C#如何调用Word并打开一个Word文档
2013/05/08 面试题
Python里面search()和match()的区别
2016/09/21 面试题
体育学院毕业生自荐信
2013/11/03 职场文书
低碳环保倡议书
2014/04/14 职场文书
网站推广策划方案
2014/06/04 职场文书
2014年党员自我评价材料
2014/09/22 职场文书
企业三严三实学习心得体会
2014/10/13 职场文书
综合素质评价自我评价
2015/03/06 职场文书