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.AutoComplete.js中文修正版(支持firefox)
Apr 09 Javascript
jquery.post用法之type设置问题
Feb 24 Javascript
BAT及各大互联网公司2014前端笔试面试题--JavaScript篇
Oct 29 Javascript
JS实现消息来时让网页标题闪动效果的方法
Apr 20 Javascript
JavaScript获取IP获取的是IPV6 如何校验
Jun 12 Javascript
微信公众号-获取用户信息(网页授权获取)实现步骤
Oct 21 Javascript
Bootstrap select多选下拉框实现代码
Dec 23 Javascript
微信小程序page的生命周期和音频播放及监听实例详解
Apr 07 Javascript
详解如何使用webpack打包Vue工程
May 27 Javascript
实战node静态文件服务器的示例代码
Mar 08 Javascript
JavaScript实现简单的图片切换功能(实例代码)
Apr 10 Javascript
js实现碰撞检测
Jan 29 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分页效率终结版(推荐)
2013/07/01 PHP
php将远程图片保存到本地服务器的实现代码
2015/08/03 PHP
PHP设计模式之观察者模式实例
2016/02/22 PHP
PHP进制转换实例分析(2,8,16,36,64进制至10进制相互转换)
2017/02/04 PHP
php实现微信企业付款到个人零钱功能
2018/10/09 PHP
JavaScript去掉数组中的重复元素
2011/01/13 Javascript
一个JQuery写的点击上下滚动的小例子
2011/08/27 Javascript
超级好用的jQuery圆角插件 Corner速成
2014/08/31 Javascript
javascript转换日期字符串为Date日期对象的方法
2015/02/13 Javascript
异步安全加载javascript文件的方法
2015/07/21 Javascript
用nodeJS搭建本地文件服务器的几种方法小结
2017/03/16 NodeJs
javascript  删除select中的所有option的实例
2017/09/17 Javascript
JavaScript设计模式之构造函数模式实例教程
2018/07/02 Javascript
JSON的parse()方法介绍
2019/01/31 Javascript
jQuery分组选择器简单用法示例
2019/04/04 jQuery
实现高性能javascript的注意事项
2019/05/27 Javascript
vue-router的两种模式的区别
2019/05/30 Javascript
VUE页面中通过双击实现复制表格中内容的示例代码
2020/06/11 Javascript
[00:30]明星选手化身超级英雄!2018DOTA2亚洲邀请赛全明星赛来临!
2018/04/06 DOTA
[52:10]LGD vs Optic Supermajor小组赛D组胜者组决赛 BO3 第二场 6.3
2018/06/04 DOTA
在Python中使用__slots__方法的详细教程
2015/04/28 Python
Python列表切片用法示例
2017/04/19 Python
转换科学计数法的数值字符串为decimal类型的方法
2018/07/16 Python
python正则表达式去除两个特殊字符间的内容方法
2018/12/24 Python
python实现电子词典
2020/03/03 Python
html5调用app分享功能示例(WebViewJavascriptBridge)
2018/03/21 HTML / CSS
Fashion Eyewear美国:英国线上设计师眼镜和太阳镜的零售商
2016/08/15 全球购物
英国虚拟主机服务商:eUKhost
2016/08/16 全球购物
viagogo意大利票务平台:演唱会、体育比赛、戏剧门票
2018/01/26 全球购物
产品包装策划方案
2014/05/18 职场文书
英文感谢信格式
2015/01/21 职场文书
总经理岗位职责范本
2015/04/01 职场文书
第二次离婚起诉书
2015/05/18 职场文书
2016年大学生暑假爱心支教活动策划书
2015/11/26 职场文书
初中英语教学反思范文
2016/02/15 职场文书
深入理解CSS 中 transform matrix矩阵变换问题
2021/08/30 HTML / CSS