Javascript异步编程模型Promise模式详细介绍


Posted in Javascript onMay 08, 2014

Promise 编程模式也被称为 thenable,可以理解为 延迟后执行。每个 Promise 都拥有一个叫做 then 的唯一接口,当 Promise 失败或成功时,它就会进行回调。它代表了一种可能会长时间运行而且不一定必须完成的操作结果。这种模式不会阻塞和等待长时间的操作完成,而是返回一个代表了承诺的(promised)结果的对象。

当前的许多 JavaScript 库(如 jQuery 和 Dojo、AngularJS)均添加了这种称为 Promise 的抽象。通过这些库,开发人员能够在实际编程中使用 Promise 模式。

下面我们将以 jQuery 为例讨论 JavaScript 库是如何使用 Promise 模式的来处理异步的,其实就是通过回调的方式提供容错支持。在某个操作成功或失败或任何情况下都执行对应的回调,尽量把某段逻辑可能出现的情况都 handle 住。

首先让我们来看看 jQuery 一般是如何操作的:

var $info = $("#info");
$.ajax({
    url:"/echo/json/",
    data: { json: JSON.stringify({"name": "someValue"}) },
    type:"POST",
    success: function(response)
    {
       $info.text(response.name);
    }
});

在这个例子中,你可以看到当设置成功后会指定一个回调,是一种很好的回调方式,这并不是 Promise,jQuery 官方文档也不再推荐这种方式(http://api.jquery.com/jQuery.ajax/#jqXHR)。 当 Ajax 调用完成后,它便会执行 success 函数。根据库所使用的异步操作,你可以使用各种不同的回调(即任务是否成功,都会进行回调,做出响应)。使用 Promise 模式会简化这个过程,异步操作只需返回一个对象调用。这个 Promise 允许你调用一个叫做 then 的方法,然后让你指定回调的 function(s) 个数。

下面让我们来看看 jQuery 是如何建立 Promise 的:

var $info = $("#info");
$.ajax({
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    $info.text(response.name);
});

jQuery ajax 对象通过返回 xhr 对象实现 Promise 模式,所以我们可以调用 then 方法,这样做的优势是你可以链式调用,实现独立操作,如下所示 :

var $info = $("#info");
$.ajax({
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
    $info.text(response.name);
})
.then(function () {
    $info.append("...More");
})
.done(function () {
    $info.append("...finally!");
});

由于许多库都开始采用 Promise 模式,所以异步操作会变的非常容易。但如果站在相反的角度思考,Promise 将会是什么样子的呢?其中一个非常重要的模式是函数可以接受两种功能,一个是成功时的回调,另一个是失败时的回调。

var $info = $("#info");
$.ajax({
// Change URL to see error happen
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.then(function (response) {
// success
    $info.text(response.name);
},
function () {
// failure
    $info.text("bad things happen to good developers");
})
.always(function () {
    $info.append("...finally");
});

需要注意的是,在 jQuery 里,无论成功还是失败,我们都会使用一个调用来指定我们想要调用的。
其实这里也可以这样来写,这也是 jQuery 官方文档里推荐的方法:

var $info = $("#info");
$.ajax({
// Change URL to see error happen
    url: "/echo/json/",
    data: {
        json: JSON.stringify({
            "name": "someValue"
        })
    },
    type: "POST"
})
.done(function (response) {
  // success
  $info.text(response.name);
}).fail(function () {
  // failure
  $info.text("bad things happen to good developers");
})
.always(function () {
    $info.append("...finally");
});

下面再来看看 AngularJS 是如何使用 Promise 模式的:

var m = angular.module("myApp", []);
m.factory("dataService", function ($q) {
    function _callMe() {
        var d = $q.defer();
        setTimeout(function () {
            d.resolve();
            //defer.reject();
        }, 100);
        return d.promise;
    }
    return {
        callMe: _callMe
    };
});
function myCtrl($scope, dataService) {
    $scope.name = "None";
    $scope.isBusy = true;
    dataService.callMe()
      .then(function () {
        // Successful
        $scope.name = "success";
      },
      function () {
        // failure
        $scope.name = "failure";
      })
      .then(function () {
        // Like a Finally Clause
        $scope.isBusy = false;
      });
}

你可以在 JSFiddle 里试试这些例子,并且看看会产生哪些效果。使用 Promise 来操作异步是一种非常简单的方式,而且还可以简化你的代码,确实是一举两得的好方法。
更多关于Promise的介绍及示例,可以前往官网(http://www.promisejs.org/)查看。

Javascript 相关文章推荐
jQuery ui插件的使用方法代码实例
May 08 Javascript
顶部缓冲下拉菜单导航特效的JS代码
Aug 27 Javascript
JS图像无缝滚动脚本非常好用
Feb 10 Javascript
jQuery焦点图切换简易插件制作过程全纪录
Aug 27 Javascript
基于jQuery实现最基本的淡入淡出效果实例
Feb 02 Javascript
jQuery使用after()方法在元素后面添加多项内容的方法
Mar 26 Javascript
JavaScript常用字符串与数组扩展函数小结
Apr 24 Javascript
JavaScript在form表单中使用button按钮实现submit提交方法
Jan 23 Javascript
Angular1.x自定义指令实例详解
Mar 01 Javascript
javascript数据结构中栈的应用之符号平衡问题
Apr 11 Javascript
Vue中使用better-scroll实现轮播图组件
Mar 07 Javascript
微信公众号中的JSSDK接入及invalid signature等常见错误问题分析(全面解析)
Apr 11 Javascript
JS获取随机数函数可自定义最小值最大值
May 08 #Javascript
js数组操作常用方法
May 08 #Javascript
javascript获取和判断浏览器窗口、屏幕、网页的高度、宽度等
May 08 #Javascript
jquery mobile的触控点击事件会多次触发问题的解决方法
May 08 #Javascript
javascript操作excel生成报表示例
May 08 #Javascript
jquery的ajax跨域请求原理和示例
May 08 #Javascript
Javascript单元测试框架QUnitjs详细介绍
May 08 #Javascript
You might like
PHP学习 运算符与运算符优先级
2008/06/15 PHP
PHP遍历二维数组的代码
2011/04/22 PHP
WordPress分页伪静态加html后缀
2016/06/08 PHP
Mootools 1.2教程 正则表达式
2009/09/15 Javascript
firefox火狐浏览器与与ie兼容的2个问题总结
2010/07/20 Javascript
JQuery.ajax传递中文参数的解决方法 推荐
2011/03/28 Javascript
jQuery 联动日历实现代码
2012/05/31 Javascript
jQuery模拟超链接点击效果代码
2013/04/21 Javascript
javascript生成随机数的方法
2014/05/16 Javascript
JS跨域问题详解
2014/11/25 Javascript
jquery模拟实现鼠标指针停止运动事件
2016/01/12 Javascript
微信小程序学习(4)-系统配置app.json详解
2017/01/12 Javascript
详解支持Angular 2的表格控件
2017/01/19 Javascript
jQuery获取复选框选中的当前行的某个字段的值
2017/09/15 jQuery
基于js中的存储键值对以及注意事项介绍
2018/03/30 Javascript
如何解决vue2.0下IE浏览器白屏问题
2018/09/13 Javascript
如何制作一个Node命令行图像识别工具
2018/12/12 Javascript
使用webpack搭建vue环境的教程详解
2019/12/31 Javascript
关于引入vue.js 文件的知识点总结
2020/01/28 Javascript
详解ES6新增字符串扩张方法includes()、startsWith()、endsWith()
2020/05/12 Javascript
vue实现抽屉弹窗效果
2020/11/15 Javascript
黑科技 Python脚本帮你找出微信上删除你好友的人
2016/01/07 Python
python打印9宫格、25宫格等奇数格 满足横竖斜相加和相等
2019/07/19 Python
安装2019Pycharm最新版本的教程详解
2019/10/22 Python
萌新的HTML5 入门指南
2020/11/06 HTML / CSS
汇集了世界上最好的天然和有机美容产品:LoveLula
2018/02/05 全球购物
荷兰游戏商店:Allyouplay
2019/03/16 全球购物
灵泰克Java笔试题
2016/01/09 面试题
采购求职信
2014/03/17 职场文书
2014年国庆晚会主持词
2014/09/19 职场文书
员工工作及收入证明
2014/10/28 职场文书
干部个人考察材料
2014/12/24 职场文书
学习保证书
2015/01/17 职场文书
2015年社区流动人口工作总结
2015/05/12 职场文书
教师旷工检讨书
2015/08/15 职场文书
小学主题班会教案
2015/08/17 职场文书