详解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』名称冲突使用noConflict方法解决
Apr 22 Javascript
在JS数组特定索引处指定位置插入元素
Jul 27 Javascript
使用node.js 制作网站前台后台
Nov 13 Javascript
JS实现生成会变大变小的圆环实例
Aug 05 Javascript
轻松掌握jQuery中wrap()与unwrap()函数的用法
May 24 Javascript
JavaScript用JSONP跨域请求数据实例详解
Jan 06 Javascript
Bootstrap面板使用方法
Jan 16 Javascript
Angular17之Angular自定义指令详解
Jan 21 Javascript
JS实现的检验身份证格式并输出出生日期,年龄,性别,出生地示例
May 17 Javascript
原生js实现的金山打字小游戏(实例代码详解)
Mar 16 Javascript
如何实现js拖拽效果及原理解析
May 08 Javascript
Vue使用Ref跨层级获取组件的步骤
Jan 25 Vue.js
深入浅析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后台程序与Javascript的两种交互方式
2009/10/25 PHP
探讨PHP中this,self,parent的区别详解
2013/06/08 PHP
PHP+MySQL删除操作实例
2015/01/21 PHP
Yii2.0预定义的别名功能小结
2016/07/04 PHP
基于ThinkPHP5.0实现图片上传插件
2017/09/25 PHP
JS中setInterval、setTimeout不能传递带参数的函数的解决方案
2013/04/28 Javascript
js实现全屏漂浮广告移入光标停止移动
2013/12/02 Javascript
html5+javascript制作简易画板附图
2014/04/25 Javascript
jQuery中triggerHandler()方法用法实例
2015/01/19 Javascript
Vue.js Ajax动态参数与列表显示实现方法
2016/10/20 Javascript
详解webpack 多入口配置
2017/06/16 Javascript
Three.js利用dat.GUI如何简化试验流程详解
2017/09/26 Javascript
详解vue+vuex+koa2开发环境搭建及示例开发
2018/01/22 Javascript
cropper js基于vue的图片裁剪上传功能的实现代码
2018/03/01 Javascript
JavaScript动态加载重复绑定问题
2018/04/01 Javascript
详解js中Array的方法及技巧
2018/09/12 Javascript
JavaScript实现轮播图效果代码实例
2019/09/28 Javascript
Python_LDA实现方法详解
2017/10/25 Python
python celery分布式任务队列的使用详解
2019/07/08 Python
python实现翻转棋游戏(othello)
2019/07/29 Python
python定位xpath 节点位置的方法
2019/08/27 Python
python [:3] 实现提取数组中的数
2019/11/27 Python
python 判断txt每行内容中是否包含子串并重新写入保存的实例
2020/03/12 Python
通过代码简单了解django model序列化作用
2020/11/12 Python
CSS3哪些新特性值得称赞
2016/03/02 HTML / CSS
基于HTML5+tracking.js实现刷脸支付功能
2020/04/16 HTML / CSS
Beauty Expert美国/加拿大:购买奢侈美容产品
2018/12/05 全球购物
英国领先的维生素和营养补充剂直接供应商:Healthspan
2019/04/22 全球购物
农民致富事迹材料
2014/01/23 职场文书
大学毕业生求职自荐书
2014/06/05 职场文书
买卖合同协议书范本
2014/10/18 职场文书
先进党组织事迹材料
2014/12/26 职场文书
团代会邀请函
2015/02/02 职场文书
捐款仪式主持词
2015/07/04 职场文书
nginx安装以及配置的详细过程记录
2021/09/15 Servers
threejs太阳光与阴影效果实例代码
2022/04/05 Javascript