详解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 相关文章推荐
setTimeout和setInterval的浏览器兼容性分析
Feb 27 Javascript
当jQuery遭遇CoffeeScript的时候 使用分享
Sep 17 Javascript
JS上传图片前实现图片预览效果的方法
Mar 02 Javascript
JavaScript实现鼠标滑过图片变换效果的方法
Apr 16 Javascript
防止Node.js中错误导致进程阻塞的办法
Aug 11 Javascript
AngularJS  $on、$emit和$broadcast的使用
Sep 05 Javascript
Bootstrap禁用响应式布局的实现方法
Mar 09 Javascript
AngularJS 教程及实例代码
Oct 23 Javascript
微信小程序数据分析之自定义分析的实现
Aug 17 Javascript
深入浅析javascript函数中with
Oct 28 Javascript
总结4个方面优化Vue项目
Feb 11 Javascript
JS实现的贪吃蛇游戏案例详解
May 01 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
Windows PHP5和Apache的安装与配置
2009/06/08 PHP
7个鲜为人知却非常实用的PHP函数
2015/07/01 PHP
如何使用php脚本给html中引用的js和css路径打上版本号
2015/11/18 PHP
java模拟PHP的pack和unpack类
2016/04/13 PHP
多浏览器兼容性比较好的复制到剪贴板的js代码
2011/10/09 Javascript
JavaScript操作DOM元素的childNodes和children区别
2015/04/01 Javascript
javascript带回调函数的异步脚本载入方法实例分析
2015/07/02 Javascript
JS实现双击编辑可修改状态的方法
2015/08/14 Javascript
jquery实现简单的表单验证
2015/11/17 Javascript
jQuery插件EasyUI校验规则 validatebox验证框
2015/11/29 Javascript
jQuery图片左右滚动代码 有左右按钮实例
2016/06/20 Javascript
一道优雅面试题分析js中fn()和return fn()的区别
2016/07/05 Javascript
JS常用函数和常用技巧小结
2016/10/15 Javascript
JavaScript中数组Array.sort()排序方法详解
2017/03/01 Javascript
JavaScript实现图片切换效果
2017/08/12 Javascript
Angularjs之ngModel中的值验证绑定方法
2018/09/13 Javascript
Vue项目pdf(base64)转图片遇到的问题及解决方法
2018/10/19 Javascript
详解如何探测小程序返回到webview页面
2019/05/14 Javascript
webpack安装配置与常见使用过程详解(结合vue)
2020/06/01 Javascript
简单了解JavaScript作用域
2020/07/31 Javascript
Python 过滤字符串的技巧,map与itertools.imap
2008/09/06 Python
python保存二维数组到txt文件中的方法
2018/11/15 Python
python实现简单日期工具类
2019/04/24 Python
Django使用中间键实现csrf认证详解
2019/07/22 Python
Python 使用 PyMysql、DBUtils 创建连接池提升性能
2019/08/14 Python
windows环境中利用celery实现简单任务队列过程解析
2019/11/29 Python
python+selenium 简易地疫情信息自动打卡签到功能的实现代码
2020/08/22 Python
美国鲍勃商店:Bob’s Stores
2018/07/22 全球购物
工程项目经理岗位职责
2013/12/15 职场文书
顶撞老师检讨书
2014/02/07 职场文书
机械制造专业毕业生求职信
2014/03/02 职场文书
充分就业社区汇报材料
2014/05/07 职场文书
推荐信格式范文
2014/05/09 职场文书
幸福家庭标语
2014/06/27 职场文书
中职毕业生自我鉴定
2014/09/13 职场文书
Python使用pandas导入xlsx格式的excel文件内容操作代码
2022/12/24 Python