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图像处理—平滑处理实现原理
Dec 28 Javascript
js作用域及作用域链概念理解及使用
Apr 15 Javascript
javascript:void(0)的问题使用探讨
Apr 10 Javascript
使用BootStrap和Metroui设计的metro风格微网站或手机app界面
Oct 21 Javascript
JS实现密码框的显示密码和隐藏密码功能示例
Dec 26 Javascript
webpack打包react项目的实现方法
Jun 21 Javascript
boostrap模态框二次弹出清空原有内容的方法
Aug 10 Javascript
Nuxt.js实现校验访问浏览器类型的中间件
Aug 24 Javascript
Vue使用watch监听一个对象中的属性的实现方法
May 10 Javascript
js实现固定区域内的不重叠随机圆
Oct 24 Javascript
JavaScript浅层克隆与深度克隆示例详解
Sep 01 Javascript
微信小程序实现文件预览
Oct 22 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过滤危险html代码的函数
2008/07/22 PHP
PHP学习之数组的定义和填充
2011/04/17 PHP
10个实用的PHP正则表达式汇总
2014/10/23 PHP
Yii2隐藏frontend/web和backend/web的方法
2015/12/12 PHP
PHP Ajax实现无刷新附件上传
2016/08/17 PHP
详解PHP序列化和反序列化原理
2018/01/15 PHP
javascript数组使用调用方法汇总
2007/12/08 Javascript
javascript正则匹配汉字、数字、字母、下划线
2014/04/10 Javascript
jQuery制作的别致导航有阴影背景高亮模式窗口
2014/04/15 Javascript
jQuery中attr()和prop()在修改checked属性时的区别
2014/07/18 Javascript
7个jQuery最佳实践
2016/01/12 Javascript
jQuery简单注册和禁用全局事件的方法
2016/07/25 Javascript
jQuery基本选择器之标签名选择器
2016/09/03 Javascript
js通过keyCode值判断单击键盘上某个键,然后触发指定的事件方法
2017/02/19 Javascript
几行js代码实现自适应
2017/02/24 Javascript
JavaScript基于面向对象实现的猜拳游戏
2018/01/03 Javascript
在vue项目中使用Nprogress.js进度条的方法
2018/01/31 Javascript
如何从零开始手写Koa2框架
2019/03/22 Javascript
基于Fixed定位的框选功能的实现代码
2019/05/13 Javascript
js实现飞机大战游戏
2020/08/26 Javascript
[03:40]DOTA2英雄梦之声_第01期_炼金术士
2014/06/23 DOTA
[01:01:31]2018DOTA2亚洲邀请赛3月29日小组赛B组 Mineski VS paiN
2018/03/30 DOTA
python3.5使用tkinter制作记事本
2016/06/20 Python
Django中的ajax请求
2018/10/19 Python
python爬虫之遍历单个域名
2019/11/20 Python
适合各种场合的美食礼品:Harry & David
2016/08/03 全球购物
加拿大花店:1800Flowers.ca
2016/11/16 全球购物
Speedo澳大利亚官网:全球领先游泳品牌
2018/02/04 全球购物
异常和异常类的概念
2014/09/12 面试题
工作疏忽检讨书
2014/01/25 职场文书
四风个人对照检查材料思想汇报(办公室通用版)
2014/10/07 职场文书
简历自我评价优缺点
2015/03/11 职场文书
《植物妈妈有办法》教学反思
2016/02/23 职场文书
因个人工作失误检讨书
2019/06/21 职场文书
珍惜时间的诗歌赏析
2019/08/23 职场文书
nginx日志格式分析和修改
2022/04/28 Servers