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 相关文章推荐
js 创建快捷方式的代码(fso)
Nov 19 Javascript
移动设备web开发首选框架:zeptojs介绍
Jan 29 Javascript
JavaScript中输出信息的方法(信息确认框-提示输入框-文档流输出)
Jun 12 Javascript
Vue 2.0中生命周期与钩子函数的一些理解
May 09 Javascript
微信小程序Redux绑定实例详解
Jun 07 Javascript
vue中component组件的props使用详解
Sep 04 Javascript
vue axios同步请求解决方案
Sep 29 Javascript
bootstrap时间插件daterangepicker使用详解
Oct 19 Javascript
vue弹窗消息组件的使用方法
Sep 24 Javascript
微信小程序云开发实现云数据库读写权限
May 17 Javascript
vue解决使用$http获取数据时报错的问题
Oct 30 Javascript
手写实现JS中的new
Nov 07 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
桌面中心(一)创建数据库
2006/10/09 PHP
PHP函数学习之PHP函数点评
2012/07/05 PHP
php实现斐波那契数列的简单写法
2014/07/19 PHP
异步加载技术实现当滚动条到最底部的瀑布流效果
2014/09/16 PHP
利用PHP访问带有密码的Redis方法示例
2017/02/09 PHP
laravel Task Scheduling(任务调度)在windows下的使用详解
2019/10/22 PHP
JavaScript静态的动态
2006/09/18 Javascript
指定js可访问其它域名的cookie的方法
2007/09/18 Javascript
Jquery常用技巧收集整理篇
2010/11/14 Javascript
CodeMirror2 IE7/IE8 下面未知运行时错误的解决方法
2012/03/29 Javascript
兼容主流浏览器的jQuery+CSS 实现遮罩层的简单代码
2014/10/14 Javascript
JavaScript实现点击文字切换登录窗口的方法
2015/05/11 Javascript
Javascript中Date类型和Math类型详解
2016/02/27 Javascript
省市区三级联动jquery实现代码
2020/04/15 Javascript
扩展bootstrap的modal模态框-动态添加modal框-弹出多个modal框
2017/02/21 Javascript
深入学习 JavaScript中的函数调用
2017/03/23 Javascript
JS获取鼠标位置距浏览器窗口距离的方法示例
2017/04/11 Javascript
webpack配置sass模块的加载的方法
2017/07/30 Javascript
jQuery选择器中的特殊符号处理方法
2017/09/08 jQuery
JS实现自定义状态栏动画文字效果示例
2017/10/12 Javascript
Bootstrap table使用方法汇总
2017/11/17 Javascript
vue el-table实现自定义表头
2019/12/11 Javascript
Vue中component标签解决项目组件化操作
2020/09/04 Javascript
[02:33]2014DOTA2 TI每日综述 LGD涉险晋级DK闯入胜者组
2014/07/14 DOTA
Python提取特定时间段内数据的方法实例
2019/04/01 Python
python批量将excel内容进行翻译写入功能
2019/10/10 Python
K最近邻算法(KNN)---sklearn+python实现方式
2020/02/24 Python
django rest framework serializer返回时间自动格式化方法
2020/03/31 Python
通过实例简单了解python yield使用方法
2020/08/06 Python
html5实现输入框fixed定位在屏幕最底部兼容性
2020/07/03 HTML / CSS
表决心的诗句大全
2014/03/11 职场文书
初中学生期末评语
2014/04/24 职场文书
美国留学经济担保书
2014/05/20 职场文书
专科生就业求职信
2014/06/22 职场文书
新教师个人工作总结
2015/02/06 职场文书
HTML中的表格元素介绍
2022/02/28 HTML / CSS