详解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 相关文章推荐
javascript Demo模态窗口
Dec 06 Javascript
Extjs Ext.MessageBox.confirm 确认对话框详解
Apr 02 Javascript
YUI Compressor压缩JavaScript原理及微优化
Jan 07 Javascript
实现js保留小数点后N位的代码
Nov 13 Javascript
jquery中checkbox使用方法简单实例演示
Nov 24 Javascript
H5移动端适配 Flexible方案
Oct 24 Javascript
AngularJS使用ng-class动态增减class样式的方法示例
May 18 Javascript
Node中使用ES6语法的基础教程
Jan 05 Javascript
JS栈stack类的实现与使用方法示例
Jan 31 Javascript
js实现全选和全不选功能
Jul 28 Javascript
vscode 使用Prettier插件格式化配置使用代码详解
Aug 10 Javascript
VsCode里的Vue模板的实现
Aug 12 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
中国第一家无线电行
2021/03/01 无线电
Yii框架form表单用法实例
2014/12/04 PHP
PHP实现的DES加密解密实例代码
2016/04/06 PHP
使用PHP+Redis实现延迟任务,实现自动取消订单功能
2019/11/21 PHP
在jQuery中 常用的选择器介绍
2013/04/16 Javascript
Js nodeType 属性全面解析
2013/11/14 Javascript
jQuery实现在textarea指定位置插入字符或表情的方法
2015/03/11 Javascript
JavaScript制作简易的微信打飞机
2015/03/31 Javascript
基于jquery实现轮播焦点图插件
2016/03/31 Javascript
JS中frameset框架弹出层实例代码
2016/04/01 Javascript
基于jQuery实现的单行公告活动轮播效果
2017/08/23 jQuery
基于webpack4搭建的react项目框架的方法
2018/06/30 Javascript
js jquery 获取某一元素到浏览器顶端的距离实现方法
2018/09/05 jQuery
利用Vue构造器创建Form组件的通用解决方法
2018/12/03 Javascript
Layui实现数据表格默认全部显示(不要分页)
2019/10/26 Javascript
用vite搭建vue3应用的实现方法
2021/02/22 Vue.js
Python实现连接两个无规则列表后删除重复元素并升序排序的方法
2018/02/05 Python
python随机在一张图像上截取任意大小图片的方法
2019/01/24 Python
详解python调用cmd命令三种方法
2019/07/08 Python
jupyter notebook 增加kernel教程
2020/04/10 Python
Python小白学习爬虫常用请求报头
2020/06/03 Python
selenium自动化测试入门实战
2020/12/21 Python
Python xlwings插入Excel图片的实现方法
2021/02/26 Python
详解快速开发基于 HTML5 网络拓扑图应用
2018/01/08 HTML / CSS
中国跨境在线时尚零售商:Bellelily
2018/04/06 全球购物
美国台面电器和厨具品牌:KitchenAid
2019/04/12 全球购物
销售实习自我鉴定
2013/12/07 职场文书
数控机械专业个人的自我评价
2014/01/02 职场文书
优秀教师工作感言
2014/02/16 职场文书
最新结婚典礼主持词
2014/03/14 职场文书
大学生学习计划书
2014/09/15 职场文书
教师政风行风自查自纠报告
2014/10/21 职场文书
2014年法院个人工作总结
2014/12/17 职场文书
党员个人总结范文
2015/02/14 职场文书
入团介绍人意见范文
2015/06/04 职场文书
利用ajax+php实现商品价格计算
2021/03/31 PHP