详解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 相关文章推荐
jquery 快速回到页首的方法
Dec 05 Javascript
IE6下拉框图层问题探讨及解决
Jan 03 Javascript
js实现网页标题栏闪烁提示效果实例分析
Nov 20 Javascript
使用AngularJS来实现HTML页面嵌套的方法
Jun 17 Javascript
JS中frameset框架弹出层实例代码
Apr 01 Javascript
通过jquery实现页面的动画效果(实例代码)
Sep 18 Javascript
详解JavaScript 中getElementsByName在IE中的注意事项
Feb 21 Javascript
xmlplus组件设计系列之列表(4)
Apr 26 Javascript
在Vue中使用echarts的实例代码(3种图)
Jul 10 Javascript
jQuery实现的淡入淡出图片轮播效果示例
Aug 29 jQuery
详解适配器在JavaScript中的体现
Sep 28 Javascript
JS数据类型分类及常用判断方法
Nov 19 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/12/04 PHP
简单的PHP留言本实例代码
2010/05/09 PHP
thinkphp使用phpmailer发送邮件的方法
2014/11/24 PHP
PHP魔术方法__GET、__SET使用实例
2014/11/25 PHP
PHP children()函数讲解
2019/02/03 PHP
载入进度条 效果
2006/07/08 Javascript
js下获得客户端操作系统的函数代码(1:vista,2:windows7,3:2000,4:xp,5:2003,6:2008)
2011/10/31 Javascript
JS判断页面加载状态以及添加遮罩和缓冲动画的代码
2012/10/11 Javascript
基于JavaScript 数据类型之Boolean类型分析介绍
2013/04/19 Javascript
js实现拉伸拖动iframe的具体代码
2013/08/03 Javascript
使用JavaScript修改浏览器URL地址栏的实现代码
2013/10/21 Javascript
Extjs grid panel自带滚动条失效的解决方法
2014/09/11 Javascript
js模拟淘宝网的多级选择菜单实现方法
2015/08/18 Javascript
浅析JS原型继承与类的继承
2016/04/07 Javascript
Bootstrap3 Grid system原理及应用详解
2016/09/30 Javascript
使用JS实现图片轮播的实例(前后首尾相接)
2017/09/21 Javascript
JS实现点击复选框变更DIV显示状态的示例代码
2017/12/18 Javascript
解决npm安装Electron缓慢网络超时导致失败的问题
2018/02/06 Javascript
Vue 图片压缩并上传至服务器功能
2020/01/15 Javascript
[01:01:52]DOTA2-DPC中国联赛定级赛 SAG vs iG BO3第二场 1月9日
2021/03/11 DOTA
从零学python系列之数据处理编程实例(一)
2014/05/22 Python
详解常用查找数据结构及算法(Python实现)
2016/12/09 Python
Python实现替换文件中指定内容的方法
2018/03/19 Python
python中的常量和变量代码详解
2018/07/25 Python
解决Python安装时报缺少DLL问题【两种解决方法】
2019/07/15 Python
解决tensorflow添加ptb库的问题
2020/02/10 Python
基于Python模拟浏览器发送http请求
2020/11/06 Python
CSS3过渡transition效果实例介绍
2016/05/03 HTML / CSS
法制报告会主持词
2014/04/02 职场文书
工会换届选举方案
2014/05/21 职场文书
开展党的群众路线教育实践活动剖析材料
2014/10/13 职场文书
安全保证书怎么写
2015/02/28 职场文书
三八节祝酒词
2015/08/11 职场文书
一篇文章看懂MySQL主从复制与读写分离
2021/11/07 MySQL
教你使用VS Code的MySQL扩展管理数据库的方法
2022/01/22 MySQL
NoSQL优缺点与MongoDB数据库简介
2022/06/05 MongoDB