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 获取页面元素的位置的代码
Sep 25 Javascript
javascript删除数组重复元素的方法汇总
Jun 24 Javascript
原生javascript实现匀速运动动画效果
Feb 26 Javascript
基于jquery编写的放大镜插件
Mar 23 Javascript
微信小程序 location API实例详解
Oct 02 Javascript
javaScript 事件绑定、事件冒泡、事件捕获和事件执行顺序整理总结
Oct 10 Javascript
实例解析jQuery中如何取消后续执行内容
Dec 01 Javascript
jQuery Easyui datagrid行内实现【添加】、【编辑】、【上移】、【下移】
Dec 19 Javascript
vue cli构建的项目中请求代理与项目打包问题
Feb 26 Javascript
vue设置一开始进入的页面教程
Oct 28 Javascript
vue项目查看vue版本及cli版本的实现方式
Oct 24 Javascript
vue.js watch经常失效的场景与解决方案
Jan 07 Vue.js
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
Discuz! Passport 通行证整合
2008/03/27 PHP
基于asp+ajax和数据库驱动的二级联动菜单
2010/05/06 PHP
PHP开发框架kohana3 自定义路由设置示例
2014/07/14 PHP
WordPress用户登录框密码的隐藏与部分显示技巧
2015/12/31 PHP
PHP实现的简单分页类及用法示例
2016/05/06 PHP
PHP验证码无法显示的原因及解决办法
2017/08/11 PHP
PHP连接及操作PostgreSQL数据库的方法详解
2019/01/30 PHP
跟我一起学写jQuery插件开发方法(附完整实例及下载)
2010/04/01 Javascript
Javascript Object.extend
2010/05/18 Javascript
浅谈javascript的数据类型检测
2010/07/10 Javascript
原生JavaScript实现连连看游戏(附源码)
2013/11/05 Javascript
BootStrap Fileinput上传插件使用实例代码
2017/07/28 Javascript
vue移动端路由切换实例分析
2018/05/14 Javascript
15分钟深入了解JS继承分类、原理与用法
2019/01/19 Javascript
jQuery Migrate 插件用法实例详解
2019/05/22 jQuery
vue移动端模态框(可传参)的实现
2019/11/20 Javascript
微信小程序实现多图上传
2020/06/19 Javascript
[03:23]我的刀塔你不可能这么可爱 第一期金萌萌的故事
2014/06/20 DOTA
[01:19]DOTA2城市挑战赛报名开始 开启你的城市传奇
2018/03/23 DOTA
Python编程之序列操作实例详解
2017/07/22 Python
Python cookbook(数据结构与算法)通过公共键对字典列表排序算法示例
2018/03/15 Python
分享Pycharm中一些不为人知的技巧
2018/04/03 Python
python3中获取文件当前绝对路径的两种方法
2018/04/26 Python
python ChainMap的使用和说明详解
2019/06/11 Python
详解Python是如何实现issubclass的
2019/07/24 Python
使用Python实现画一个中国地图
2019/11/23 Python
护理专科毕业推荐信
2013/11/10 职场文书
大学生文员专业个人求职信范文
2014/01/05 职场文书
大学生未来职业生涯规划书
2014/02/15 职场文书
学校教研活动总结
2014/07/02 职场文书
大学教师师德师风演讲稿
2014/08/22 职场文书
中队活动总结
2014/08/27 职场文书
2014年英语教师工作总结
2014/12/03 职场文书
跟班学习心得体会(共6篇)
2016/01/23 职场文书
sql查询结果列拼接成逗号分隔的字符串方法
2021/05/25 SQL Server
nginx配置限速限流基于内置模块
2022/05/02 Servers