详解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操纵Cookie实现购物车程序
Feb 15 Javascript
为jquery.ui.dialog 增加“在当前鼠标位置打开”的功能
Nov 24 Javascript
jquery form 加载数据示例
Apr 21 Javascript
React实现点击删除列表中对应项
Jan 10 Javascript
js 转义字符及URI编码详解
Feb 28 Javascript
addEventListener()与removeEventListener()解析
Apr 20 Javascript
微信小程序三级联动地址选择器的实例代码
Jul 12 Javascript
vue如何通过id从列表页跳转到对应的详情页
May 01 Javascript
webstorm和.vue中es6语法报错的解决方法
May 08 Javascript
最适应的vue.js的form提交涉及多种插件【推荐】
Aug 27 Javascript
在vue项目中promise解决回调地狱和并发请求的问题
Nov 09 Javascript
解决vant框架做H5时踩过的坑(下拉刷新、上拉加载等)
Nov 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程序防止ddos,dns,集群服务器攻击的解决办法
2013/06/18 PHP
php更新mysql后获取改变行数的方法
2014/12/25 PHP
php实现的rc4加密解密类定义与用法示例
2018/08/16 PHP
PHP经典设计模式之依赖注入定义与用法详解
2019/05/21 PHP
PHP进阶学习之反射基本概念与用法分析
2019/06/18 PHP
jQuery学习笔记[1] jQuery中的DOM操作
2010/12/03 Javascript
javascript 正则表达式相关应介绍
2012/11/27 Javascript
js去字符串前后空格5种实现方法及比较
2013/04/03 Javascript
解决Jquery鼠标经过不停滑动的问题
2014/03/03 Javascript
JQuery简单实现锚点链接的平滑滚动
2015/05/03 Javascript
微信小程序 Audio API详解及实例代码
2016/09/30 Javascript
vue动态组件实现选项卡切换效果
2017/03/08 Javascript
Webpack如何引入bootstrap的方法
2017/06/17 Javascript
vue-router重定向和路由别名的使用讲解
2019/01/19 Javascript
微信小程序学习笔记之本地数据缓存功能详解
2019/03/29 Javascript
小程序实现简单语音聊天的示例代码
2020/07/24 Javascript
jquery实现拖拽小方块效果
2020/12/10 jQuery
[13:16]INFAMOUS vs VGJ T BO3
2018/06/07 DOTA
Python脚本处理空格的方法
2016/08/08 Python
python数据类型_字符串常用操作(详解)
2017/05/30 Python
python通过elixir包操作mysql数据库实例代码
2018/01/31 Python
django 多数据库配置教程
2018/05/30 Python
python 创建一个空dataframe 然后添加行数据的实例
2018/06/07 Python
python爬虫框架scrapy实现模拟登录操作示例
2018/08/02 Python
详解Python 多线程 Timer定时器/延迟执行、Event事件
2019/06/27 Python
python3 深浅copy对比详解
2019/08/12 Python
python yield关键词案例测试
2019/10/15 Python
selenium中get_cookies()和add_cookie()的用法详解
2020/01/06 Python
TensorFlow MNIST手写数据集的实现方法
2020/02/05 Python
Python实现多线程下载脚本的示例代码
2020/04/03 Python
CSS3 transforms应用于背景图像的解决方法
2019/04/16 HTML / CSS
销售行政专员岗位职责
2014/06/10 职场文书
行政部经理助理岗位职责
2014/06/15 职场文书
工地门卫岗位职责范本
2014/07/01 职场文书
安全责任书怎么写
2014/07/28 职场文书
CSS3实现的3D隧道效果
2021/04/27 HTML / CSS