详解Javacript和AngularJS中的Promises


Posted in Javascript onFebruary 09, 2016

比如页面调用google地图的api时就使用到了promise。

function success(position){
  var cords = position.coords;
  console.log(coords.latitude + coords.longitude);
}

function error(err){
  console.warn(err.code+err.message)
}

navigator.geolocation.getCurrentPosition(success, error);

■ 如何处理多个异步方法

如果有很多异步方法需要按序执行呢?async1(success, failure), async2(success, failure), ...asyncN(success, failure),该如何处理呢?

最简单的,可能会这样写:

async1(function(){
  async2(function(){
    ...
    asyncN(null, null);
    ...
  }, null)
}, null)

以上的代码是比较难维护的。

我们可以让所有的异步方法执行完毕后出来一个通知。

var counter = N;
function success(){
  counter--;
  if(counter === 0){
    alert('done');
  }
}

async1(success);
async2(success);
...
asyncN(success);

■ 什么是Promise和Deferred

deferred表示异步操作的结果,提供了一个显示操作结果和状态的接口,并提供了一个可以获取该操作结果相关的promise实例。deferred是可以改变操作状态的。

promise提供了一个用来和相关deferred交互的接口。

当创建一个deferred,相当于一个pending状态;
当执行resolve方法,相当于一个resolved状态。
当执行reject方法,相当于一个rejected状态。

我们可以在创建deferred之后,定义回调函数,而回调函数在得到resolved和rejected的状态提示后开始执行。异步方法不需要知道回调函数如何操作,只需要在得到resolved或rejected状态后通知回调函数开始执行。

■ 基本用法

→ 创建deferred

var myFirstDeferred = $q.defer();

这里,对于myFirstDeferred这个deferred,状态是pending,接下来,当异步方法执行成功,状态变成resolved,当异步方法执行失败,状态变成rejected。

→ Resolve或Reject这个dererred

假设有这样的一个异步方法:async(success, failure) 

async(function(value){
  myFirstDeferred.resolve(value);
}, function(errorReason){
  myFirstDeferred.reject(errorReason);
})

在AngularJS中,$q的resolve和reject不依赖上下文,大致可以这样写:

async(myFirstDeferred.resolve, myFirstDeferred.reject);

→ 使用deferred中的promise

var myFirstPromise = myFirstDeferred.promise;

myFirstPromise
  .then(function(data){
  
  }, function(error){
  
  })

deferred可以有多个promise.

var anotherDeferred = $q.defer();

anotherDeferred.promise
  .then(function(data){
  
  },function(error){
  
  })
  
//调用异步方法
async(anotherDeferred.resolve, anotherDeferred.reject);

anotherDeferred.promise
  .then(function(data){
  
  }, function(error){
  
  })

以上,如果异步方法async成功执行,两个success方法都会被调用。

→ 通常把异步方法包裹到一个函数中

function getData(){
  var deferred = $q.defer();
  async(deferred.resolve,deferred.reject);
  return deferred.promise;
}

//deferred的promise属性记录了达到resolved, reject状态所需要执行的success和error方法
var dataPromise = getData();
dataPromise
  .then(function(data){
    console.log('success');
  }, function(error){
    console.log('error');
  })

如果只关注success回调函数该如何写呢?

dataPromise
  .then(function(data){
    console.log('success');
  })

如果只关注error回调函数该如何写呢?

dataPromise
  .then(null, function(error){
    console.log('error');
  })
  
或

dataPromise.catch(function(error){
  console.log('error');
})

如果不管回调成功或失败都返回相同的结果呢?

var finalCallback = function(){
  console.log('不管回调成功或失败都返回这个结果');
}

dataPromise.then(finalCallback, finalCallback);

dataPromise.finally(finalCallback);
■ 值链式

假设有一个异步方法,使用deferred.resolve返回一个值。

function async(value){
  var deferred = $q.defer();
  var result = value / 2;
  deferred.resolve(result);
  return deferred.promise;
}

既然返回的是promise,我们就可以不断then, then下去的。

var promise = async(8)
  .then(function(x){
    return x+1;
  })
  .then(function(x){
    return x*2;
  })
  
promise.then(function(x){
  console.log(x);
})

以上,resolve出的值成为每一个链式的实参。

■ Promise链式

function async1(value){
  var deferred = $q.defer();
  var result = value * 2;
  deferred.resolve(result);
  return deferred.promise;
}

function async2(value){
  var deferred = $q.defer();
  var result = value + 1;
  deferred.resolve(result);
  return deferred.promise;
}

var promise = async1(10)
  .then(function(x){
    return async2(x);
  })
  
promise.then(function(x){
  console.log(x);
})

当然一种更易读的写法是:

function logValue(value){
  console.log(value);
}

async1(10)
  .then(async2)
  .then(logValue);

async1方法的返回值成为then方法中的success方法中的实参。

如果从捕获异常的角度,还可以这样写:

async1()
  .then(async2)
  .then(async3)
  .catch(handleReject)
  .finally(freeResources);

■ $q.reject(reason)   

使用该方法能够让deferred呈现error状态,并给出一个出现error的理由。

var promise = async().then(function(value){
  if(true){
    return value;
  } else {
    return $q.reject('value is not satisfied');
  }
})

■ $q.when(value)

返回一个promise并带上值。

function getDataFromBackend(query){
  var data = searchInCache(query);
  if(data){
    return $q.when(data);
  } else {
    reutrn makeAasyncBackendCall(query);
  }
}

■ $q.all(promisesArr)

等待所有promise执行完成。

var allPromise = $q.all([
  async1(),
  async2(),
  ...
  asyncN();
])

allProise.then(function(values){
  var value1 = values[0],
    value2 = values[1],
    ...
    valueN = values[N];
    
  console.log('all done');
})

以上就是本文的详细内容,希望对大家学习有所帮助,新年快乐!

Javascript 相关文章推荐
弹出层之1:JQuery.Boxy (一) 使用介绍
Oct 06 Javascript
JavaScript DOM事件(笔记)
Apr 08 Javascript
JS使用cookie实现DIV提示框只显示一次的方法
Nov 05 Javascript
jQuery图片旋转插件jQueryRotate.js用法实例(附demo下载)
Jan 21 Javascript
BootStrap智能表单实战系列(七)验证的支持
Jun 13 Javascript
JS实现禁止高频率连续点击的方法【基于ES6语法】
Apr 25 Javascript
canvas绘制爱心的几种方法总结(推荐)
Oct 31 Javascript
基于angular-utils-ui-breadcrumbs使用心得(分享)
Nov 03 Javascript
关于vue里页面的缓存详解
Nov 04 Javascript
Vue两个版本的区别和使用方法(更深层次了解)
Feb 16 Javascript
Element Collapse 折叠面板的使用方法
Jul 26 Javascript
微信小程序自定义支持图片的弹窗
Dec 21 Javascript
深入浅析JavaScript面向对象和原型函数
Feb 06 #Javascript
基于JavaScript实现图片点击弹出窗口而不是保存
Feb 06 #Javascript
javascript+css3 实现动态按钮菜单特效
Feb 06 #Javascript
Angularjs全局变量被作用域监听的正确姿势
Feb 06 #Javascript
JavaScript仿商城实现图片广告轮播实例代码
Feb 06 #Javascript
简介AngularJS中$http服务的用法
Feb 06 #Javascript
详解AngularJS中$http缓存以及处理多个$http请求的方法
Feb 06 #Javascript
You might like
PHP输出控制功能在简繁体转换中的应用
2006/10/09 PHP
解决了Ajax、MySQL 和 Zend Framework 的乱码问题
2009/03/03 PHP
php array_walk() 数组函数
2011/07/12 PHP
php实现的click captcha点击验证码类实例
2014/09/23 PHP
php查询whois信息的方法
2015/06/08 PHP
PHP类的声明与实例化及构造方法与析构方法详解
2016/01/26 PHP
php基于jquery的ajax技术传递json数据简单实例
2016/04/15 PHP
IE与Firefox下javascript getyear年份的兼容性写法
2007/12/20 Javascript
根据对象的某一属性进行排序的js代码(如:name,age)
2010/08/10 Javascript
实现变速回到顶部的JavaScript代码
2011/05/09 Javascript
onkeydown事件解决按回车键直接提交数据的需求
2013/04/11 Javascript
什么是cookie?js手动创建和存储cookie
2014/05/27 Javascript
javascript获取隐藏元素(display:none)的高度和宽度的方法
2014/06/06 Javascript
jquery实现html页面 div 假分页有原理有代码
2014/09/06 Javascript
在Linux系统中搭建Node.js开发环境的简单步骤讲解
2016/01/26 Javascript
漂亮! js实现颜色渐变效果
2016/08/12 Javascript
JS实现倒计时(天数、时、分、秒)
2016/11/16 Javascript
JavaScript实现移动端页面按手机屏幕分辨率自动缩放的最强代码
2017/08/18 Javascript
react quill中图片上传由默认转成base64改成上传到服务器的方法
2019/10/30 Javascript
JavaScript常用工具函数大全
2020/05/06 Javascript
[01:43]倾听DOTA2英雄之声 魅惑魔女国服配音鉴赏
2013/06/06 DOTA
[00:14]护身甲盾
2019/03/06 DOTA
python获取指定网页上所有超链接的方法
2015/04/04 Python
python多线程之事件Event的使用详解
2018/04/27 Python
对Python中plt的画图函数详解
2018/11/07 Python
Django实现文件上传和下载功能
2019/10/06 Python
PyCharm使用Docker镜像搭建Python开发环境
2019/12/26 Python
xadmin使用formfield_for_dbfield函数过滤下拉表单实例
2020/04/07 Python
Python实现JS解密并爬取某音漫客网站
2020/10/23 Python
学生就业推荐信
2013/11/13 职场文书
便利店投资的创业计划书
2014/01/12 职场文书
文明工地标语
2014/06/16 职场文书
美术教师个人总结
2015/02/06 职场文书
品质保证书格式
2015/02/28 职场文书
导游词之金鞭溪风景区
2019/09/12 职场文书
如何用 Python 子进程关闭 Excel 自动化中的弹窗
2021/05/07 Python