详解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复选框CHECKBOX全选,取消全选
Aug 30 Javascript
js下获取div中的数据的原理分析
Apr 07 Javascript
jQuery获取样式中颜色值的方法
Jan 29 Javascript
js实现div层缓慢收缩与展开的方法
May 11 Javascript
jquery表单对象属性过滤选择器实例分析
May 18 Javascript
JavaScript File API文件上传预览
Feb 02 Javascript
D3.js实现雷达图的方法详解
Sep 22 Javascript
微信小程序之选项卡的实现方法
Sep 29 Javascript
Vue配合iView实现省市二级联动的示例代码
Jul 27 Javascript
对于防止按钮重复点击的尝试详解
Apr 22 Javascript
JavaScript工具库之Lodash详解
Jun 15 Javascript
vue3+typescript实现图片懒加载插件
Oct 26 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
一个oracle+PHP的查询的例子
2006/10/09 PHP
PHP新手用的Insert和Update语句构造类
2012/03/31 PHP
php开启openssl的方法
2014/05/15 PHP
php去除二维数组的重复项方法
2015/11/03 PHP
PHP读书笔记整理_结构语句详解
2016/07/01 PHP
PHP图像识别技术原理与实现
2016/10/27 PHP
项目实践之javascript技巧
2007/12/06 Javascript
jquery animate 动画效果使用说明
2009/11/04 Javascript
js 剪切板的用法(clipboardData.setData)与js match函数介绍
2013/11/19 Javascript
javaScript如何生成xmlhttp
2013/12/16 Javascript
扩展IE中一些不兼容的方法如contains、startWith等等
2014/01/09 Javascript
AngularJS入门教程之AngularJS模型
2016/04/18 Javascript
JS实现n秒后自动跳转的两种方法
2020/11/30 Javascript
如何使用angularJs
2017/05/08 Javascript
关于定制FileField中的上传文件名称问题
2017/08/22 Javascript
Three.js利用dat.GUI如何简化试验流程详解
2017/09/26 Javascript
vue给组件传递不同的值方法
2018/09/29 Javascript
详解Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
2018/10/12 Javascript
提升node.js中使用redis的性能遇到的问题及解决方法
2018/10/30 Javascript
vue-cli3环境变量与分环境打包的方法示例
2019/02/18 Javascript
JavaScript的Proxy可以做哪些有意思的事儿
2019/06/15 Javascript
js实现自定义滚动条的示例
2020/10/27 Javascript
简介Python中用于处理字符串的center()方法
2015/05/18 Python
python版本单链表实现代码
2018/09/28 Python
Python Series从0开始索引的方法
2018/11/06 Python
uwsgi+nginx部署Django项目操作示例
2018/12/04 Python
Python 实现国产SM3加密算法的示例代码
2020/09/21 Python
解释一下Windows的消息机制
2014/01/30 面试题
小学国庆节活动方案
2014/02/11 职场文书
教师党员公开承诺书
2014/03/25 职场文书
讲文明懂礼貌演讲稿
2014/09/11 职场文书
小区的门卫岗位职责
2014/10/01 职场文书
2014年女职工工作总结
2014/11/27 职场文书
联村联户简报
2015/07/21 职场文书
关于Vue Router的10条高级技巧总结
2021/05/06 Vue.js
Python Numpy库的超详细教程
2022/04/06 Python