详解Angular.js的$q.defer()服务异步处理


Posted in Javascript onNovember 06, 2016

首先本文以个人目前项目的部分代码为例说明为什么要用deferred。

function getBase64(img){//传入图片路径,返回base64
   function getBase64Image(img,width,height) {
    var canvas = document.createElement("canvas");
    canvas.width = width ? width : img.width;
    canvas.height = height ? height : img.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
    var dataURL = canvas.toDataURL();
    return dataURL;
   }
   var image = new Image();
   image.crossOrigin = '';
   image.src = img;

   var base64='';
   if(img){
    image.onload =function (){
     base64=getBase64Image(image);
     console.log(base64);//位置一
    }
    console.log(base64);//位置二
   }
  }

就这段代码,我想要在位置二处使用base64,然后结果呢?

两处位置都打印了,位置一得到base64,ok,没问题。当我在位置二想使用base64时,问题来了?onload队列的问题,位置二总是无法正确的获取到想要的base64,这个时候就可以考虑异步问题了。

我相信大家应该和我一样,遇到这种情况第一反应应该是deferred让函数异步执行。

那么,我讲以上代码使用deferred之后,问题完美解决!

function getBase64(img){//传入图片路径,返回base64
    function getBase64Image(img,width,height) {
     var canvas = document.createElement("canvas");
     canvas.width = width ? width : img.width;
     canvas.height = height ? height : img.height;
     var ctx = canvas.getContext("2d");
     ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
     var dataURL = canvas.toDataURL();
     return dataURL;
    }
    var image = new Image();
    image.crossOrigin = '';
    image.src = img;

    var deferred=$q.defer();
    if(img){
     image.onload =function (){
     deferred.resolve(getBase64Image(image));
     }
     return deferred.promise;
    }
    }

getBase64('https://img.alicdn.com/bao/uploaded/TB1qimQIpXXXXXbXFXXSutbFXXX.jpg')
    .then(function(base64){
     var binaryblob = function (s, type) {//blob对象
      var byteString = atob(s);
      var array = [];
      for (var i = 0; i < byteString.length; i++) {
       array.push(byteString.charCodeAt(i));
      }
      return new Blob([new Int8Array(array)], {type: type});
     };
     var binaryPictureBlob = function (dataUrl, filterHead) {//上传base64去头
      var s = filterHead ? dataUrl.replace(/^data:image\/(png|jpeg|pjpeg|bmp|gif|x-png);base64,/, "") : dataUrl;
      return binaryblob(s, "image/jpeg");
     };
     var pic=binaryPictureBlob(base64,true);//blob对象
     //然后调接口将blob对象上传
    });

问题解决了,我又想到了分享!那么我将我的拙见写出来,请不吝赐教!

什么是defer?

$q是Angular的一种内置服务,它可以使你异步地执行函数,并且当函数执行完成时或异常时它允许你使用函数的返回值或返回执行状态通知等。

defer的意思是延迟,$q.defer() 可以创建一个deferred延迟对象实例,实例旨在暴露派生的Promise 实例,Promise就是一种对执行结果不确定的一种预先定义,如果成功,就xx;如果失败,就xx,就像事先给出了一些承诺。

用法:

一个最完整的写法:

var defer1 = $q.defer();

  function fun() {
   var deferred = $q.defer();
   $timeout(function () {
    deferred.notify("notify");
    if (iWantResolve) {
     deferred.resolve("resolved");
    } else {
     deferred.reject("reject");
    }
   }, 500);
   return deferred.promise;
  }

  $q.when(fun())
    .then(function(success){
     console.log("success");
     console.log(success);
    },function(err){
     console.log("error");
     console.log(err);
    },function(notify){
     console.log("notify");
     console.log(notify);
    })
    .catch(function(reson){
     console.log("catch");
     console.log(reson);
    })
    .finally(function(final){
     console.log('finally');
     console.log(final);
    });

1、通过$q服务注册一个延迟对象

var deferred=$q.defer();

2、成功解决(resolve)了其派生的promise。参数value将来会被用作successCallback(success){}函数的参数value。

deferred.resolve(success)

3、未成功解决其派生的promise。参数reason被用来说明未成功的原因。此时deferred实例的promise对象将会捕获一个任务未成功执行的错误,promise.catch(errorCallback(reason){...})

deferred.reject(reason)

4、更新promise的执行状态通知

deferred.notify("notify");

5、对promise进行处理

$q.when(fun())
    .then(function(success){
     console.log("success");
     console.log(success);
    },function(err){
     console.log("error");
     console.log(err);
    },function(notify){
     console.log("notify");
     console.log(notify);
    })
    .catch(function(reson){
     console.log("catch");
     console.log(reson);
    })
    .finally(function(final){
     console.log('finally');
     console.log(final);
    });

这里一般简写为:

fun().then(successCallback, errorCallback, notifyCallback);

注:

deferred的方法中的参数都返回给了promise与callback的参数都是一一对应的,如:

deferred.resolve(success)的success对应successCallback(success)的success。

这里在探讨下暂时很少用的$q.all().

$q.all()在多个promise必须执行成功后才能执行成功回调,传递值为数组或哈希值,数组中每个值为与Index对应的promise对象。

这个方法可以将每个promise里的某些重复代码或者判断,只需要在$q.all()的回调处理一次即可,简化了代码与工作量。

写法为:

var iWantResolve = true;//没有实际意思,测试运行resolve或reject

  function promise1() {
   return $q(function (resolve, reject) {
    $timeout(function () {
     if (iWantResolve) {
      resolve("promise1 resolved");
     } else {
      reject("promise1 reject");
     }
    }, 1000)
   })
  }
  promise1()
    .then(function (s1) {//success callback
     console.log(s1);
    })
    .catch(function (err1) {//error callback
     console.log(err1);
    });

  function promise2() {
   var deferred = $q.defer();
   $timeout(function () {
    deferred.notify("promise2 notify");
    if (iWantResolve) {
     deferred.resolve("promise2 resolved");
    } else {
     deferred.reject("promise2 reject");
    }
   }, 500);
   return deferred.promise;
  }

  promise2()
    .then(function (s2) {
     console.log(s2);
    }, function (err2) {
     console.log(err2);
    });

  $q.all([promise1(), promise2()])
    .then(function (dataArr) {
     //promise都成功执行后的回调函数
     console.log("$q.all: ", dataArr);
    }, function (err) {
     console.log("$q.all: ", err)
    });

像这个例子,每个promise回调都打印了返回值,那么可以用$q.all()处理在其回调打印dataArr,则包含了所有promise返回值!

jquery和angular的deferred用法大致相同,但有两处要注意的地方:

jquery:

defer=$.Deferred();
defer.promise();

angular:

var deferred=$q.defer();
deferred.promise;

总结

以上便是我对angular的$q、deferred、promise的一些浅显的理解,希望对大家的学习或者能有所帮助,如果有疑问大家可以留言交流。望各位大神多多评论、指教……

最后附上:

jquery中文网的deferred介绍:

http://www.jquery123.com/category/deferred-object/

一位大神对jquery的deferred的总结!

阮一峰:http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html

 

Javascript 相关文章推荐
jquery 指南/入门基础
Nov 30 Javascript
提高网站性能之 如何对待JavaScript
Oct 31 Javascript
js怎么判断flash swf文件是否加载完毕
Aug 14 Javascript
gulp-htmlmin压缩html的gulp插件实例代码
Jun 06 Javascript
微信小程序开发之录音机 音频播放 动画实例 (真机可用)
Dec 08 Javascript
vue2.0+ 从插件开发到npm发布的示例代码
Apr 28 Javascript
JavaScript执行环境及作用域链实例分析
Aug 01 Javascript
vue3.0 CLI - 2.3 - 组件 home.vue 中学习指令和绑定
Sep 14 Javascript
CKeditor富文本编辑器使用技巧之添加自定义插件的方法
Jun 14 Javascript
layer关闭当前窗口页面以及确认取消按钮的方法
Sep 09 Javascript
Vue3.0 响应式系统源码逐行分析讲解
Oct 14 Javascript
JavaScrip如果基于url实现图片下载
Jul 03 Javascript
Bootstrap 3.x打印预览背景色与文字显示异常的解决
Nov 06 #Javascript
d3.js实现简单的网络拓扑图实例代码
Nov 06 #Javascript
HTML5 JS压缩图片并获取图片BASE64编码上传
Nov 16 #Javascript
JS控制div跳转到指定的位置的几种解决方案总结
Nov 05 #Javascript
xcode中获取js文件的路径方法(推荐)
Nov 05 #Javascript
在js里怎么实现Xcode里的callFuncN方法(详解)
Nov 05 #Javascript
jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
Nov 05 #Javascript
You might like
php4的session功能评述(三)
2006/10/09 PHP
有关 PHP 和 MySQL 时区的一点总结
2008/03/26 PHP
PHP字符过滤函数去除字符串最后一个逗号(rtrim)
2013/03/26 PHP
php自动提交表单的方法(基于fsockopen与curl)
2016/05/09 PHP
php中分页及SqlHelper类用法实例
2017/01/12 PHP
yii框架无限极分类的实现方法
2017/04/08 PHP
js实现的日期操作类DateTime函数代码
2010/03/16 Javascript
JS日期和时间选择控件升级版(自写)
2013/08/02 Javascript
js实现九宫格图片半透明渐显特效的方法
2015/02/16 Javascript
js+html5实现canvas绘制简单矩形的方法
2015/06/05 Javascript
JavaScript实现网页加载进度条代码超简单
2015/09/21 Javascript
学习JavaScript设计模式(单例模式)
2015/11/26 Javascript
只要1K 纯JS脚本送你一朵3D红色玫瑰
2016/08/09 Javascript
Javascript json object 与string 相互转换的简单实现
2016/09/27 Javascript
详解vue2路由vue-router配置(懒加载)
2017/04/08 Javascript
Angular在模板驱动表单中自定义校验器的方法
2017/08/09 Javascript
react-native组件中NavigatorIOS和ListView结合使用的方法
2017/09/30 Javascript
进一步了解Python中的XML 工具
2015/04/13 Python
Python随机生成数模块random使用实例
2015/04/13 Python
Python中的XML库4Suite Server的介绍
2015/04/14 Python
利用Python中unittest实现简单的单元测试实例详解
2017/01/09 Python
PyQt5每天必学之关闭窗口
2018/04/19 Python
使用Python通过win32 COM实现Word文档的写入与保存方法
2018/05/08 Python
Python实现读取txt文件并转换为excel的方法示例
2018/05/17 Python
python 拼接文件路径的方法
2018/10/23 Python
详解python使用turtle库来画一朵花
2019/03/21 Python
使用 Django Highcharts 实现数据可视化过程解析
2019/07/31 Python
PHP高级工程师面试问题推荐
2013/01/18 面试题
const char*, char const*, char*const的区别是什么
2014/07/09 面试题
Hibernate持久层技术
2013/12/16 面试题
物流司机岗位职责
2013/12/28 职场文书
党务公开方案
2014/05/06 职场文书
2016年情人节问候语
2015/11/11 职场文书
为Java项目添加Redis缓存的方法
2021/05/18 Redis
Python pandas读取CSV文件的注意事项(适合新手)
2021/06/20 Python
JavaScript文档对象模型DOM
2021/11/20 Javascript