详解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 相关文章推荐
解放web程序员的输入验证
Oct 06 Javascript
用javascript获得地址栏参数的两种方法
Nov 08 Javascript
第二次聊一聊JS require.js模块化工具的基础知识
Apr 17 Javascript
jQuery内容折叠效果插件用法实例分析(附demo源码)
Apr 28 Javascript
使用bootstrap3开发响应式网站
May 12 Javascript
必备的JS调试技巧汇总
Jul 20 Javascript
Javascript基础学习笔记(菜鸟必看篇)
Jul 22 Javascript
详解Vue-Cli 异步加载数据的一些注意点
Aug 12 Javascript
vue中的scope使用详解
Oct 29 Javascript
在element-ui的el-tree组件中用render函数生成el-button的实例代码
Nov 05 Javascript
详解小程序设置缓存并且不覆盖原有数据
Apr 15 Javascript
Vue实现数据表格合并列rowspan效果
Nov 30 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检测useragent版本示例
2014/03/24 PHP
PHP学习笔记(一) 简单了解PHP
2014/08/04 PHP
PHP用FTP类上传文件视频等的简单实现方法
2016/09/23 PHP
js读取本地excel文档数据的代码
2010/11/11 Javascript
JS代码放在head和body中的区别分析
2011/12/01 Javascript
JavaScript按位运算符的应用简析
2014/02/04 Javascript
js简单实现Select互换数据的方法
2015/08/17 Javascript
基于javascript实现浏览器滚动条快到底部时自动加载数据
2015/11/30 Javascript
jQuery animate easing使用方法图文详解
2016/06/17 Javascript
简单易懂的天气插件(代码分享)
2017/02/04 Javascript
Nodejs进阶之服务端字符编解码和乱码处理
2017/09/04 NodeJs
vue 导航菜单刷新状态不消失,显示对应的路由界面操作
2020/08/06 Javascript
vue使用keep-alive实现组件切换时保存原组件数据方法
2020/10/30 Javascript
[01:30]2016国际邀请赛中国区预选赛神秘商店火爆开启
2016/06/26 DOTA
Python的加密模块md5、sha、crypt使用实例
2014/09/28 Python
零基础写python爬虫之urllib2使用指南
2014/11/05 Python
利用Python抓取行政区划码的方法
2016/11/28 Python
Python使用剪切板的方法
2017/06/06 Python
python tkinter canvas 显示图片的示例
2019/06/13 Python
PyCharm刷新项目(文件)目录的实现
2020/02/14 Python
浅析python标准库中的glob
2020/03/13 Python
django Model层常用验证器及自定义验证器详解
2020/07/15 Python
python 实现学生信息管理系统的示例
2020/11/28 Python
Python爬取你好李焕英豆瓣短评生成词云的示例代码
2021/02/24 Python
美体小铺加拿大官方网站:The Body Shop加拿大
2016/10/30 全球购物
美国用餐电影院:Alamo Drafthouse Cinema
2020/01/23 全球购物
护士求职推荐信范文
2013/11/23 职场文书
创业计划书如何编写
2014/02/06 职场文书
置业顾问岗位职责
2014/03/02 职场文书
环境工程专业自荐信
2014/03/03 职场文书
小学教师学习党的群众路线教育实践活动心得体会
2014/10/31 职场文书
饭店服务员岗位职责
2015/02/09 职场文书
英语教师个人工作总结
2015/02/09 职场文书
军训后的感想
2015/08/07 职场文书
CSS极坐标的实例代码
2021/06/03 HTML / CSS
实例详解Python的进程,线程和协程
2022/03/13 Python