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 相关文章推荐
javascript 精粹笔记
May 09 Javascript
使用jQuery解决IE与FireFox下createElement方法的差异
Nov 14 Javascript
设计模式中的facade外观模式在JavaScript开发中的运用
May 18 Javascript
vue插件tab选项卡使用小结
Oct 27 Javascript
用jQuery旋转插件jqueryrotate制作转盘抽奖
Feb 10 Javascript
使用vue中的v-for遍历二维数组的方法
Mar 07 Javascript
使用jQuery如何写一个含验证码的登录界面
May 13 jQuery
JavaScript实现秒杀时钟倒计时
Sep 29 Javascript
js常用方法、检查是否有特殊字符串、倒序截取字符串操作完整示例
Jan 26 Javascript
vue vantUI tab切换时 list组件不触发load事件的问题及解决方法
Feb 14 Javascript
手把手带你入门微信小程序新框架Kbone的使用
Feb 25 Javascript
在Vue.js中使用TypeScript的方法
Mar 19 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环境――Appserv
2006/12/13 PHP
PHP轻量级数据库操作类Medoo增加、删除、修改、查询例子
2014/07/04 PHP
PHP函数eval()介绍和使用示例
2014/08/20 PHP
基于php实现七牛抓取远程图片
2015/12/01 PHP
微信红包随机生成算法php版
2016/07/21 PHP
Yii2表单事件之Ajax提交实现方法
2017/05/04 PHP
PHP设计模式(四)原型模式Prototype实例详解【创建型】
2020/05/02 PHP
基于PHP的登录和注册的功能的实现
2020/08/06 PHP
js获取触发事件元素在整个网页中的绝对坐标(示例代码)
2013/12/13 Javascript
JavaScript核心语法总结(推荐)
2016/06/02 Javascript
js中使用使用原型(prototype)定义方法的好处详解
2016/07/04 Javascript
jQuery事件处理的特征(事件命名机制)
2016/08/23 Javascript
JS实现的样式切换功能tableCSS实例
2016/12/30 Javascript
jQuery EasyUI tree增加搜索功能的实现方法
2017/04/27 jQuery
快速将Vue项目升级到webpack3的方法步骤
2017/09/14 Javascript
基于vue cli重构多页面脚手架过程详解
2018/01/23 Javascript
解决修复npm安装全局模块权限的问题
2018/05/17 Javascript
JQuery事件冒泡和默认行为代码实例
2020/05/13 jQuery
python使用Apriori算法进行关联性解析
2017/12/21 Python
pycharm+django创建一个搜索网页实例代码
2018/01/24 Python
python入门教程 python入门神图一张
2018/03/05 Python
用python编写第一个IDA插件的实例
2018/05/29 Python
python_opencv用线段画封闭矩形的实例
2018/12/05 Python
python ---lambda匿名函数介绍
2019/03/13 Python
pytorch numpy list类型之间的相互转换实例
2019/08/18 Python
通过实例解析python创建进程常用方法
2020/06/19 Python
python使用requests库爬取拉勾网招聘信息的实现
2020/11/20 Python
HTML5边玩边学(2)基础绘图实现方法
2010/09/21 HTML / CSS
html5拖拽应用记录及注意点
2020/05/27 HTML / CSS
会计学毕业生求职信
2014/06/25 职场文书
会计专业应届生自荐信
2014/06/28 职场文书
一年级数学上册复习计划
2015/01/17 职场文书
二年级语文下册复习计划
2015/01/19 职场文书
高中运动会广播稿
2015/08/19 职场文书
社区结对共建协议书
2016/03/23 职场文书
2016年领导干部廉政承诺书
2016/03/24 职场文书