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 相关文章推荐
ExtJS PropertyGrid中使用Combobox选择值问题
Jun 13 Javascript
javascript hashtable 修正版 下载
Dec 30 Javascript
JS获取html对象的几种方式介绍
Dec 05 Javascript
使用js完成节点的增删改复制等的操作
Jan 02 Javascript
jqTransform美化表单
Oct 10 Javascript
jQuery版本升级踩坑大全
Jan 12 Javascript
angular实现spa单页面应用实例
Jul 10 Javascript
JavaScript上传文件时不用刷新页面方法总结(推荐)
Aug 15 Javascript
Javascript删除数组里的某个元素
Feb 28 Javascript
微信小程序判断页面是否从其他页面返回的实例代码
Jul 03 Javascript
解决vue打包后vendor.js文件过大问题
Jul 03 Javascript
vue实现输入框自动跳转功能
May 20 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多文件上传实例
2015/07/09 PHP
PHP性能分析工具xhprof的安装使用与注意事项
2017/12/19 PHP
PHP基于curl实现模拟微信浏览器打开微信链接的方法示例
2019/02/15 PHP
javascript 隐藏/显示指定的区域附HTML元素【legend】用法
2010/03/05 Javascript
jQuery.get、jQuery.getJSON、jQuery.post无法返回JSON问题的解决方法
2011/07/28 Javascript
CSS鼠标响应事件经过、移动、点击示例介绍
2013/09/04 Javascript
简单漂亮的js弹窗可自由拖拽且兼容大部分浏览器
2013/10/22 Javascript
常用的JS验证和函数汇总
2014/12/23 Javascript
JavaScript常用小技巧小结
2014/12/29 Javascript
JQuery中基础过滤选择器用法实例分析
2015/05/18 Javascript
JavaScript制作简单的日历效果
2016/03/10 Javascript
JS修改地址栏参数实例代码
2016/06/14 Javascript
基于jQuery ligerUI实现分页样式
2016/09/18 Javascript
从0开始学Vue
2016/10/27 Javascript
JavaScript实现类似拉勾网的鼠标移入移出效果
2016/10/27 Javascript
原生JavaScript实现Tooltip浮动提示框特效
2017/03/07 Javascript
Angular中封装fancyBox(图片预览)遇到问题小结
2017/09/01 Javascript
Vue.js自定义指令学习使用详解
2019/10/19 Javascript
跟老齐学Python之做一个小游戏
2014/09/28 Python
python批量生成本地ip地址的方法
2015/03/23 Python
python获取外网IP并发邮件的实现方法
2017/10/01 Python
教你用一行Python代码实现并行任务(附代码)
2018/02/02 Python
Python3获取拉勾网招聘信息的方法实例
2019/04/03 Python
python requests证书问题解决
2019/09/05 Python
Python龙贝格法求积分实例
2020/02/29 Python
对python pandas中 inplace 参数的理解
2020/06/27 Python
Python根据字典的值查询出对应的键的方法
2020/09/30 Python
七年级数学教学反思
2014/01/22 职场文书
商场中秋节活动方案
2014/02/07 职场文书
秋天的雨教学反思
2014/04/27 职场文书
2014学校领导四风问题对照检查材料思想汇报
2014/09/22 职场文书
2014年个人总结范文
2015/03/09 职场文书
婚宴父母致辞
2015/07/27 职场文书
Windows下使用Nginx+Tomcat做负载均衡的完整步骤
2021/03/31 Servers
Django中session进行权限管理的使用
2021/07/09 Python
Python turtle编写简单的球类小游戏
2022/03/31 Python