详解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 相关文章推荐
两个SUBMIT按钮,如何区分处理
Aug 22 Javascript
又一个小巧的图片预加载类
May 05 Javascript
jQuery登陆判断简单实现代码
Apr 21 Javascript
解决jquery插件冲突的问题
Jan 23 Javascript
iscroll碰到Select无法选择下拉刷新的解决办法
May 21 Javascript
jQuery多个版本和其他js库冲突的解决方法
Aug 11 Javascript
Bootstrap轮播插件使用代码
Oct 11 Javascript
如何在Angular2中使用jQuery及其插件的方法
Feb 09 Javascript
Angular 4依赖注入学习教程之ValueProvider的使用(七)
Jun 04 Javascript
详解使用vuex进行菜单管理
Dec 21 Javascript
vue.js实现的幻灯片功能示例
Jan 18 Javascript
vue 解决数组赋值无法渲染在页面的问题
Oct 28 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/06 新手入门
关于PHP结束标签的使用细节探讨及联想
2013/03/04 PHP
thinkPHP框架可添加js事件的分页类customPage.class.php完整实例
2017/03/16 PHP
PHP+MySQL实现输入页码跳转到指定页面功能示例
2018/06/01 PHP
PHP使用DOM对XML解析处理操作示例
2019/07/04 PHP
一组JS创建和操作表格的函数集合
2009/05/07 Javascript
Javascript简单改变表单元素背景的方法
2015/07/15 Javascript
javascript中html字符串转化为jquery dom对象的方法
2015/08/27 Javascript
JS控制按钮10秒钟后可用的方法
2015/12/22 Javascript
探析浏览器执行JavaScript脚本加载与代码执行顺序
2016/01/12 Javascript
jquery制做精致的倒计时特效
2016/06/13 Javascript
iOS + node.js使用Socket.IO框架进行实时通信示例
2017/04/14 Javascript
详解vue2.0的Element UI的表格table列时间戳格式化
2017/06/13 Javascript
jQuery实现滚动效果
2017/11/17 jQuery
详解如何在vue项目中引入elementUI组件
2018/02/11 Javascript
JavaScript编写开发动态时钟
2020/07/29 Javascript
javascript实现倒计时提示框
2021/03/02 Javascript
[01:11:27]2018DOTA2亚洲邀请赛小组赛 A组加赛 Newbee vs Optic
2018/04/03 DOTA
[01:03:09]完美世界DOTA2联赛PWL S2 Forest vs SZ 第二场 11.25
2020/11/26 DOTA
Python多线程学习资料
2012/12/19 Python
python爬虫入门教程之点点美女图片爬虫代码分享
2014/09/02 Python
Python之列表实现栈的工作功能
2019/01/28 Python
详解python tkinter教程-事件绑定
2019/03/28 Python
对PyQt5中树结构的实现方法详解
2019/06/17 Python
Python Selenium安装及环境配置的实现
2020/03/17 Python
Python实现Excel自动分组合并单元格
2021/02/22 Python
css3圆角边框和边框阴影示例
2014/05/05 HTML / CSS
年度考核自我鉴定
2014/02/02 职场文书
学生周末长期请假条
2014/02/15 职场文书
元旦红领巾广播稿
2014/02/19 职场文书
幼儿园元旦家长感言
2014/02/27 职场文书
请假条怎么写
2014/04/10 职场文书
英语读书笔记
2015/07/02 职场文书
大学生社区义工服务心得体会
2016/01/22 职场文书
让人感觉高大上的讲话稿怎么写?
2019/07/08 职场文书
Vue Element UI自定义描述列表组件
2021/05/18 Vue.js