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 相关文章推荐
js 提交和设置表单的值
Dec 19 Javascript
JavaScript 闭包在封装函数时的简单分析
Nov 28 Javascript
checkbox全选/取消全选以及checkbox遍历jQuery实现代码
Dec 02 Javascript
js substr、substring和slice使用说明小记
Sep 15 Javascript
javascript实现颜色渐变的方法
Oct 30 Javascript
javascript中创建对象的几种方法总结
Nov 01 Javascript
JavaScript中判断对象类型的几种方法总结
Nov 11 Javascript
JS实现超过长度限制后自动跳转下一款文本框的方法
Feb 23 Javascript
JavaScript中通过prototype属性共享属性和方法的技巧实例
Mar 13 Javascript
jQuery实现的可编辑表格完整实例
Jun 20 Javascript
Javascript循环删除数组中元素的几种方法示例
May 18 Javascript
JS严格模式知识点总结
Feb 27 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/11/22 PHP
PHP fopen 读取带中文URL地址的一点见解
2012/09/25 PHP
PHP对称加密算法(DES/AES)类的实现代码
2017/11/14 PHP
PHP var关键字相关原理及使用实例解析
2020/07/11 PHP
左侧是表头的JS表格控件(自写,网上没有的)
2013/06/04 Javascript
json数据的列循环示例
2013/09/06 Javascript
通过遮罩层实现浮层DIV登录的js代码
2014/02/07 Javascript
document.write的几点使用心得
2014/05/14 Javascript
html的DOM中Event对象onblur事件用法实例
2015/01/21 Javascript
javascript跨域总结之window.name实现的跨域数据传输
2015/11/01 Javascript
详解AngularJS Filter(过滤器)用法
2015/12/28 Javascript
JS去除空格和换行的正则表达式(推荐)
2016/06/14 Javascript
详解vue-cli 构建Vue项目遇到的坑
2017/08/30 Javascript
利用jQuery实现简单的拖曳效果实例代码
2017/10/20 jQuery
jQuery实现新闻播报滚动及淡入淡出效果示例
2018/03/23 jQuery
jQuery实现简单聊天室
2020/02/08 jQuery
基于JS实现快速读取TXT文件
2020/08/25 Javascript
[01:08]DOTA2“血战之命”预告片
2017/08/12 DOTA
Python BeautifulSoup中文乱码问题的2种解决方法
2014/04/22 Python
Python中time模块与datetime模块在使用中的不同之处
2015/11/24 Python
基于循环神经网络(RNN)的古诗生成器
2018/03/26 Python
使用实现pandas读取csv文件指定的前几行
2018/04/20 Python
Python操作注册表详细步骤介绍
2020/02/05 Python
Python docutils文档编译过程方法解析
2020/06/23 Python
使用CSS3和Checkbox实现JQuery的一些效果
2015/08/03 HTML / CSS
实例讲解CSS3中Transform的perspective属性的用法
2016/04/22 HTML / CSS
HTML5中的拖放实现详解
2017/08/23 HTML / CSS
美国最大的家庭鞋类零售商之一:Shoe Carnival
2017/10/06 全球购物
Napapijri西班牙在线商店:夹克、外套、运动衫等
2020/11/05 全球购物
腾讯公司的一个sql题
2013/01/22 面试题
婚礼秀策划方案
2014/05/19 职场文书
个人工作决心书
2015/09/22 职场文书
推普标语口号大全
2015/12/26 职场文书
python解决12306登录验证码的实现
2021/04/18 Python
SpringBoot集成Druid连接池连接MySQL8.0.11
2021/07/02 Java/Android
CentOS7 minimal 最小化安装网络设置过程
2022/12/24 Servers