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 相关文章推荐
mapper--图片热点区域高亮组件官方站点
Dec 22 Javascript
js获取dom的高度和宽度(可见区域及部分等等)
Jun 13 Javascript
Jqgrid设置全选(选择)及获取选择行的值示例代码
Dec 28 Javascript
ext前台接收action传过来的json数据示例
Jun 17 Javascript
jQuery标签替换函数replaceWith()的使用例子
Aug 28 Javascript
node.js中的fs.fchown方法使用说明
Dec 16 Javascript
javascript 判断整数方法分享
Dec 16 Javascript
jQuery的context属性用法实例
Dec 27 Javascript
JavaScript弹出新窗口并控制窗口移动到指定位置的方法
Apr 06 Javascript
AngularJS 作用域详解及示例代码
Aug 17 Javascript
Node.js读取文件内容示例
Mar 07 Javascript
vue+SSM实现验证码功能
Dec 07 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中设置index.php文件为只读的方法
2013/02/06 PHP
Yii2搭建后台并实现rbac权限控制完整实例教程
2016/04/28 PHP
javascript Zifa FormValid 0.1表单验证 代码打包下载
2007/06/08 Javascript
javascript写的一个链表实现代码
2009/10/25 Javascript
jQuery把表单元素变为json对象
2013/11/06 Javascript
AspNet中使用JQuery boxy插件的确认框
2015/05/20 Javascript
使用Chrome浏览器调试AngularJS应用的方法
2015/06/18 Javascript
详解JavaScript中的4种类型识别方法
2015/09/14 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
深入理解Node.js的HTTP模块
2016/10/12 Javascript
基于bootstrap实现收缩导航条
2017/03/17 Javascript
JavaScript实现三级联动菜单实例代码
2017/06/26 Javascript
MUI实现上拉加载和下拉刷新效果
2017/06/30 Javascript
JavaScript实现简单的双色球(实例讲解)
2017/07/31 Javascript
基于JavaScript实现评论框展开和隐藏功能
2017/08/25 Javascript
vue2.0+ 从插件开发到npm发布的示例代码
2018/04/28 Javascript
js实现GIF动图分解成多帧图片上传
2019/10/24 Javascript
js正则匹配多个全部数据问题
2019/12/20 Javascript
[47:43]Alliance vs KG 2019国际邀请赛小组赛 BO2 第一场 8.16
2019/08/18 DOTA
Python装饰器使用示例及实际应用例子
2015/03/06 Python
浅谈Python中数据解析
2015/05/05 Python
详解Python文本操作相关模块
2017/06/22 Python
PyQt5每天必学之带有标签的复选框
2018/04/19 Python
Python实现的各种常见分布算法示例
2018/12/13 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
python实现本地批量ping多个IP的方法示例
2019/08/07 Python
解决pytorch多GPU训练保存的模型,在单GPU环境下加载出错问题
2020/06/23 Python
python re.match()用法相关示例
2021/01/27 Python
文化与传播毕业生求职信
2014/03/09 职场文书
机关单位动员会主持词
2014/03/20 职场文书
优秀学生党员先进事迹材料
2014/05/29 职场文书
特岗教师个人总结
2015/02/10 职场文书
医生个人年终总结
2015/02/28 职场文书
诚信考试主题班会
2015/08/17 职场文书
2016年“5.12”护士节慰问信
2015/11/30 职场文书
原生JS封装vue Tab切换效果
2021/04/28 Vue.js