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 相关文章推荐
AJAX分页的代码(后台asp.net)
Feb 14 Javascript
jquery自定义属性(类型/属性值)
May 21 Javascript
浅析jquery某一元素重复绑定的问题
Jan 03 Javascript
用javascript替换URL中的参数值示例代码
Jan 27 Javascript
javascript等号运算符使用详解
Apr 16 Javascript
JS实现点击按钮后框架内载入不同网页的方法
May 05 Javascript
BootStrap日期控件在模态框中选择时间下拉菜单无效的原因及解决办法(火狐下不能点击)
Aug 18 Javascript
javascript 中的console.log和弹出窗口alert
Aug 30 Javascript
JavaScrip数组删除特定元素的几种方法总结
Sep 06 Javascript
解决Vue.js 2.0 有时双向绑定img src属性失败的问题
Mar 14 Javascript
Vue2.0中三种常用传值方式(父传子、子传父、非父子组件传值)
Aug 16 Javascript
JavaScript如何实现元素全排列实例代码
May 14 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循环获取GET和POST值的代码
2008/04/09 PHP
解析php防止form重复提交的方法
2013/07/01 PHP
用HTML/JS/PHP方式实现页面延时跳转的简单实例
2016/07/18 PHP
PHP开发之用微信远程遥控服务器
2018/01/25 PHP
PHP实现的简单留言板功能示例【基于thinkPHP框架】
2018/12/07 PHP
javascript类继承机制的原理分析
2009/09/12 Javascript
jQuery内容过滤选择器用法分析
2015/02/10 Javascript
jQuery实现转动随机数抽奖效果的方法
2015/05/21 Javascript
Bootstrap基本插件学习笔记之折叠(22)
2016/12/08 Javascript
详谈DOM简介及节点、属性、查找节点的方法
2017/11/16 Javascript
JS计算距当前时间的时间差实例
2017/12/29 Javascript
微信小程序如何获取用户信息
2018/01/26 Javascript
详解从买域名到使用pm2部署node.js项目全过程
2018/03/07 Javascript
react-router4按需加载(踩坑填坑)
2019/01/06 Javascript
微信小程序上传图片到php服务器的方法
2019/05/23 Javascript
浅析vue-router中params和query的区别
2019/12/24 Javascript
javascript canvas封装动态时钟
2020/09/30 Javascript
python框架django基础指南
2016/09/08 Python
Python序列操作之进阶篇
2016/12/08 Python
python操作mysql数据库
2017/03/05 Python
恢复百度云盘本地误删的文件脚本(简单方法)
2017/10/21 Python
python实现对文件中图片生成带标签的txt文件方法
2018/04/27 Python
python循环定时中断执行某一段程序的实例
2019/06/29 Python
Python 列表去重去除空字符的例子
2019/07/20 Python
美国女孩服装购物网站:Justice
2017/03/04 全球购物
八年级历史教学反思
2014/01/10 职场文书
演讲比赛获奖感言
2014/02/02 职场文书
法院先进个人事迹材料
2014/05/04 职场文书
环保建议书500字
2014/05/14 职场文书
教师批评与自我批评发言稿
2014/10/15 职场文书
2015年财务试用期工作总结
2014/12/24 职场文书
大学生实习介绍信
2015/05/05 职场文书
追讨欠款律师函
2015/05/27 职场文书
2015七夕情人节宣传语
2015/07/14 职场文书
导游词之澳门玫瑰圣母堂
2019/12/03 职场文书
Springboot配置suffix指定mvc视图的后缀方法
2021/07/03 Java/Android