详解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 text()要注意啦
Oct 30 Javascript
js escape,unescape解决中文乱码问题的方法
May 26 Javascript
jQuery1.5.1 animate方法源码阅读
Apr 05 Javascript
javascript预加载图片、css、js的方法示例介绍
Oct 14 Javascript
用JS将搜索的关键字高亮显示实现代码
Nov 08 Javascript
jQuery 插件封装的方法
Nov 16 Javascript
jquery ajaxfileupload异步上传插件使用详解
Feb 08 Javascript
node.js实现登录注册页面
Apr 08 Javascript
Angular实现响应式表单
Aug 04 Javascript
webpack中的热刷新与热加载的区别
Apr 09 Javascript
layui点击导航栏刷新tab页的示例代码
Aug 14 Javascript
JavaScript实现身份证验证代码实例
Aug 26 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验证码类(分享)
2013/08/06 PHP
ThinkPHP CURD方法之data方法详解
2014/06/18 PHP
ThinkPHP快速入门实例教程之数据分页
2014/07/01 PHP
php给图片加文字水印
2015/07/31 PHP
jQuery 性能优化指南 (1)
2009/05/21 Javascript
在线一元二次方程计算器实例(方程计算器在线计算)
2013/12/22 Javascript
js图片实时加载提供网页打开速度
2014/09/11 Javascript
AngularJS实现表单手动验证和表单自动验证
2015/12/09 Javascript
javaScript+turn.js实现图书翻页效果实例代码
2017/02/16 Javascript
微信小程序城市定位的实现实例(获取当前所在国家城市信息)
2017/05/17 Javascript
webpack构建vue项目的详细教程(配置篇)
2017/07/17 Javascript
JavaScript Drum Kit 指南(纯 JS 模拟敲鼓效果)
2017/07/23 Javascript
详解Angular4 路由设置相关
2017/08/26 Javascript
bootstrap table实现双击可编辑、添加、删除行功能
2017/09/27 Javascript
原生JS写Ajax的请求函数功能
2017/12/22 Javascript
在react-router4中进行代码拆分的方法(基于webpack)
2018/03/08 Javascript
JavaScript变量声明var,let.const及区别浅析
2018/04/23 Javascript
vue2.0的虚拟DOM渲染思路分析
2018/08/09 Javascript
js判断浏览器的环境(pc端,移动端,还是微信浏览器)
2020/12/24 Javascript
js get和post请求实现代码解析
2020/02/06 Javascript
一起来了解一下JavaScript的预编译(小结)
2021/03/01 Javascript
[07:09]DOTA2-DPC中国联赛 正赛 Ehome vs Elephant 选手采访
2021/03/11 DOTA
Django中使用group_by的方法
2015/05/26 Python
使用apidocJs快速生成在线文档的实例讲解
2018/02/07 Python
python 多线程中join()的作用
2020/10/29 Python
python 爬虫如何实现百度翻译
2020/11/16 Python
python中re模块知识点总结
2021/01/17 Python
html5定位并在百度地图上显示的示例
2014/04/27 HTML / CSS
Html5实现文件异步上传功能
2017/05/19 HTML / CSS
专业实习自我鉴定
2013/10/29 职场文书
校园报刊亭的创业计划书
2014/01/02 职场文书
2015年元旦文艺晚会总结(学院)
2014/11/28 职场文书
求职自我评价怎么写
2015/03/09 职场文书
Python中requests做接口测试的方法
2021/05/30 Python
怎么禁用Windows 11快照布局? win11不使用快照布局的技巧
2021/11/21 数码科技
进阶篇之linux环境下安装MySQL数据库
2022/04/09 MySQL