详解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中关于执行环境的杂谈
Aug 14 Javascript
一个JQuery操作Table的代码分享
Mar 30 Javascript
jQuery给多个不同元素添加class样式的方法
Mar 26 Javascript
JavaScript设置表单上传时文件个数的方法
Aug 11 Javascript
微信小程序 开发工具快捷键整理
Oct 31 Javascript
JavaScript 深层克隆对象详解及实例
Nov 03 Javascript
JS匿名函数实例分析
Nov 26 Javascript
Bootstrap源码解读表单(2)
Dec 22 Javascript
详解能在多种前端框架下使用的表格控件
Jan 11 Javascript
区别JavaScript函数声明与变量声明
Sep 12 Javascript
JavaScript惰性求值的一种实现方法示例
Jan 11 Javascript
原生js实现放大镜组件
Jan 22 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实现阳历到农历转换的类实例
2015/03/07 PHP
PHP实现的蚂蚁爬杆路径算法代码
2015/12/03 PHP
ThinkPHP 3使用OSS的方法
2018/07/19 PHP
PHP中使用mpdf 导出PDF文件的实现方法
2018/10/22 PHP
ThinkPHP5 的简单搭建和使用详解
2018/11/15 PHP
Yii框架where查询用法实例分析
2019/10/22 PHP
关于Laravel参数验证的一些疑与惑
2019/11/19 PHP
运用Windows XP附带的Msicuu.exe、Msizap.exe来彻底卸载顽固程序
2007/04/21 Javascript
一次失败的jQuery优化尝试小结
2011/02/06 Javascript
Javascript Request获取请求参数如何实现
2012/11/28 Javascript
js 实现菜单上下显示附效果图
2013/11/21 Javascript
网站内容禁止复制和粘贴、另存为的js代码
2014/02/26 Javascript
js 设置缓存及获取设置的缓存
2014/05/08 Javascript
JavaScript实现的一个日期格式化函数分享
2014/12/06 Javascript
jQuery处理json数据返回数组和输出的方法
2015/03/11 Javascript
JQuery中DOM实现事件移除的方法
2015/06/13 Javascript
angularjs 源码解析之scope
2016/08/22 Javascript
Vuejs第七篇之Vuejs过渡动画案例全面解析
2016/09/05 Javascript
BootStrap tab选项卡使用小结
2020/08/09 Javascript
禁用backspace网页回退功能的实现代码
2016/11/15 Javascript
Restify中接入Socket.io报Error:Can’t set headers的错误解决
2017/03/28 Javascript
浅谈JavaScript闭包
2019/04/09 Javascript
[04:01]2014DOTA2国际邀请赛 TITAN告别Ohaiyo期望明年再战
2014/07/15 DOTA
[39:53]完美世界DOTA2联赛PWL S2 LBZS vs Forest 第一场 11.19
2020/11/19 DOTA
python 执行终端/控制台命令的例子
2019/07/12 Python
Django Admin设置应用程序及模型顺序方法详解
2020/04/01 Python
德国的各种媒体在线商店:Thalia.de(书籍、电子书、玩具等)
2020/10/08 全球购物
工程造价专业大学生自荐信
2013/10/01 职场文书
30年同学聚会邀请函
2014/01/25 职场文书
父亲婚礼答谢词
2015/01/04 职场文书
委托书格式要求
2015/01/28 职场文书
鉴史问廉观后感
2015/06/10 职场文书
运动会加油稿
2015/07/22 职场文书
MySQL 自定义变量的概念及特点
2021/05/13 MySQL
Python软件包安装的三种常见方法
2022/07/07 Python
DQL数据查询语句使用示例
2022/12/24 MySQL