详解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获取网页中的js、css、Flash等文件
Dec 20 Javascript
jQuery 改变CSS样式基础代码
Feb 11 Javascript
js中window.open()的所有参数详细解析
Jan 09 Javascript
JavaScript实现自动生成网页元素功能(按钮、文本等)
Nov 21 Javascript
JavaScript截取、切割字符串的技巧
Jan 07 Javascript
AngularJs Understanding the Controller Component
Sep 02 Javascript
JS用斜率判断鼠标进入DIV四个方向的方法
Nov 07 Javascript
JS实现点击下拉菜单把选择的内容同步到input输入框内的实例
Jan 23 Javascript
vue数据传递--我有特殊的实现技巧
Mar 20 Javascript
js实现同一个页面,多个enter事件绑定的示例
Oct 10 Javascript
pm2启动ssr失败的解决方法
Jun 29 Javascript
这15个Vue指令,让你的项目开发爽到爆
Oct 11 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实现MySQL更新记录的代码
2008/06/07 PHP
在PHP中利用wsdl创建标准webservice的实现代码
2011/12/07 PHP
PHP Class&Object -- 解析PHP实现二叉树
2013/06/25 PHP
PHP 以POST方式提交XML、获取XML,解析XML详解及实例
2016/10/26 PHP
php多进程应用场景实例详解
2019/07/22 PHP
js 模拟实现类似c#下的hashtable的简单功能代码
2010/01/24 Javascript
基于jQuery的Spin Button自定义文本框数值自增或自减
2010/07/17 Javascript
(跨浏览器基础事件/浏览器检测/判断浏览器)经验代码分享
2013/01/24 Javascript
node.js中的http.get方法使用说明
2014/12/14 Javascript
jQuery控制frames及frame页面JS的方法
2016/03/08 Javascript
jQuery子元素过滤选择器用法示例
2016/09/09 Javascript
BootStrop前端框架入门教程详解
2016/12/25 Javascript
微信小程序通过api接口将json数据展现到小程序示例
2017/01/20 Javascript
Vue.js中组件中的slot实例详解
2017/07/17 Javascript
JavaScript闭包和回调详解
2017/08/09 Javascript
javascript  删除select中的所有option的实例
2017/09/17 Javascript
Rollup处理并打包JS文件项目实例代码
2018/05/31 Javascript
jQuery动态移除与增加onclick属性的方法详解
2018/06/07 jQuery
vue-cli 使用axios的操作方法及整合axios的多种方法
2018/09/12 Javascript
vue如何使用async、await实现同步请求
2019/12/09 Javascript
解决vue初始化项目一直停在downloading template的问题
2020/11/09 Javascript
打印出python 当前全局变量和入口参数的所有属性
2009/07/01 Python
Python高级应用实例对比:高效计算大文件中的最长行的长度
2014/06/08 Python
windows下安装Python的XlsxWriter模块方法
2018/05/03 Python
用Python实现二叉树、二叉树非递归遍历及绘制的例子
2019/08/09 Python
pytorch 图像预处理之减去均值,除以方差的实例
2020/01/02 Python
Python爬虫实现百度翻译功能过程详解
2020/05/29 Python
python 字符串的驻留机制及优缺点
2020/06/19 Python
html5拖曳操作 HTML5实现网页元素的拖放操作
2013/01/02 HTML / CSS
Ray-Ban雷朋瑞典官方网站:全球领先的太阳眼镜品牌
2019/08/22 全球购物
商务英语求职自荐信范文
2013/12/24 职场文书
医院学雷锋活动策划方案
2014/02/15 职场文书
横店影视城导游词
2015/02/06 职场文书
董存瑞观后感
2015/06/11 职场文书
干货分享:推荐信写作技巧!
2019/06/21 职场文书
Nginx本地配置SSL访问的实例教程
2022/05/30 Servers