详解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中的公有、私有、特权和静态成员用法分析
Nov 20 Javascript
Lua表达式和控制结构学习笔记
Dec 15 Javascript
AngularJs表单验证实例代码解析
Nov 29 Javascript
详解angular2封装material2对话框组件
Mar 03 Javascript
jQuery实现QQ空间汉字转拼音功能示例
Jul 10 jQuery
javascript 中模板方法单例的实现方法
Oct 17 Javascript
深入浅析vue组件间事件传递
Dec 29 Javascript
Element-ui自定义table表头、修改列标题样式、添加tooltip、:render-header使用
Apr 11 Javascript
微信小程序实现watch监听
Jun 04 Javascript
在Vue中使用Echarts实例图的方法实例
Oct 10 Javascript
Ant design vue中的联动选择取消操作
Oct 31 Javascript
JavaScript实现表单验证功能
Dec 09 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
全国FM电台频率大全 - 7 吉林省
2020/03/11 无线电
php 文件上传系统手记
2009/10/26 PHP
php+ajax实现无刷新文件上传功能(ajaxuploadfile)
2018/02/11 PHP
详解PHP队列的实现
2019/03/14 PHP
Yii框架ACF(accessController)简单权限控制操作示例
2019/04/26 PHP
两个select之间option的互相添加操作(jquery实现)
2009/11/12 Javascript
dojo学习第二天 ajax异步请求之绑定列表
2011/08/29 Javascript
jquery 取子节点及当前节点属性值
2014/07/25 Javascript
jquery.idTabs 选项卡使用示例代码
2014/09/03 Javascript
JavaScript 学习笔记之基础中的基础
2015/01/13 Javascript
jQuery实现hover合成事件的方法
2015/08/06 Javascript
AngularJs Scope详解及示例代码
2016/09/01 Javascript
jquery遍历标签中自定义的属性方法
2016/09/17 Javascript
JavaScript实现DOM对象选择器
2016/09/24 Javascript
基于vue2的table分页组件实现方法
2017/03/20 Javascript
浅谈webpack性能榨汁机(打包速度优化)
2019/01/09 Javascript
Javascript和jquery在selenium的使用过程
2019/10/31 jQuery
node.js中事件触发器events的使用方法实例分析
2019/11/23 Javascript
Vue-router编程式导航的两种实现代码
2021/03/04 Vue.js
简化Python的Django框架代码的一些示例
2015/04/20 Python
Python Selenium 之关闭窗口close与quit的方法
2019/02/13 Python
django将网络中的图片,保存成model中的ImageField的实例
2019/08/07 Python
centos7中安装python3.6.4的教程
2019/12/11 Python
详解Python实现进度条的4种方式
2020/01/15 Python
CSS3属性background-size使用指南
2014/12/09 HTML / CSS
来自圣地亚哥的实惠太阳镜:Knockaround
2018/08/27 全球购物
Urban Decay官方网站:美国化妆品品牌
2020/06/04 全球购物
路德维希•贝克(LUDWIG BECK)中文官网:德国大型美妆百货
2020/09/19 全球购物
工程专业求职自荐书范文
2014/02/08 职场文书
小学生作文批改评语
2014/12/25 职场文书
2015大学自主招生自荐信范文
2015/03/04 职场文书
2015年农村党员干部主题教育活动总结
2015/03/25 职场文书
2015年度培训工作总结范文
2015/04/02 职场文书
贷款收入证明范本
2015/06/12 职场文书
实习员工转正的评语汇总,以备不时之需
2019/12/17 职场文书
MySQL 字符集 character
2022/05/04 MySQL