详解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 .ajax 在IE下卡死问题的解决方法
Oct 26 Javascript
javascript时区函数介绍
Sep 14 Javascript
IE下JS读取xml文件示例代码
Aug 05 Javascript
二叉树先序遍历的非递归算法具体实现
Jan 09 Javascript
jquery实现弹出层完美居中效果
Mar 03 Javascript
javascript冒泡排序小结
Apr 10 Javascript
Vue.js实现列表清单的操作方法
Nov 15 Javascript
微信小程序实现topBar底部选择栏效果
Jul 20 Javascript
IE9 elementUI文件上传的问题解决
Oct 17 Javascript
javascript面向对象创建对象的方式小结
Jul 29 Javascript
JS实现电脑虚拟键盘打字测试
Jun 24 Javascript
JS Object构造函数之Object.freeze
Apr 28 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 多个submit提交表单 处理方法
2009/07/07 PHP
PHP解析url并得到url参数方法总结
2018/10/11 PHP
PHP常见过waf webshell以及最简单的检测方法
2019/05/21 PHP
js校验表单后提交表单的三种方法总结
2014/02/28 Javascript
jQuery实现平滑滚动页面到指定锚点链接的方法
2015/07/15 Javascript
javascript 实现文本使用省略号替代(超出固定高度的情况)
2017/02/21 Javascript
js获取ip和地区
2017/03/10 Javascript
JavaScript设计模式之单例模式详解
2017/06/09 Javascript
JS实现的文字间歇循环滚动效果完整示例
2018/02/13 Javascript
JS表单传值和URL编码转换
2018/03/03 Javascript
Three.js实现简单3D房间布局
2018/12/30 Javascript
Angular Excel 导入与导出的实现代码
2019/04/17 Javascript
微信小程序音乐播放器开发
2019/11/20 Javascript
element中的$confirm的使用
2020/04/26 Javascript
基于javascript原生判断DOM是否加载完毕
2020/10/14 Javascript
[27:28]Ti4 冒泡赛第二天 iG vs NEWBEE 1
2014/07/15 DOTA
Python函数式编程
2017/07/20 Python
python 接口_从协议到抽象基类详解
2017/08/24 Python
python使用socket创建tcp服务器和客户端
2018/04/12 Python
Python元组知识点总结
2019/02/18 Python
Python3.5装饰器原理及应用实例详解
2019/04/30 Python
Python爬取YY评级分数并保存数据实现过程解析
2020/06/01 Python
class类在python中获取金融数据的实例方法
2020/12/10 Python
5分钟让你掌握css3阴影、倒影、渐变小技巧(小编推荐)
2016/08/15 HTML / CSS
用HTML5制作视频拼图的教程
2015/05/13 HTML / CSS
Unix如何添加新的用户
2014/08/20 面试题
中专生自荐信
2013/10/12 职场文书
管理科学大学生求职信
2013/11/13 职场文书
母婴店促销方案
2014/03/05 职场文书
机关作风整顿个人整改措施思想汇报
2014/09/29 职场文书
选调生挂职锻炼工作总结
2015/10/23 职场文书
导游词之丽江普济寺
2019/10/22 职场文书
CSS中float高度塌陷问题的四种解决方案
2022/04/18 HTML / CSS
阿里云服务器Ubuntu 20.04上安装Odoo 15
2022/05/20 Servers
MySQL选择合适的备份策略和备份工具
2022/06/01 MySQL