详解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阻止事件冒泡 event.stopPropagation
Dec 11 Javascript
JS如何将数字类型转化为没3个一个逗号的金钱格式
Jan 27 Javascript
让浏览器DOM元素最后加载的js方法
Jul 29 Javascript
JavaScript基于ajax编辑信息用法实例
Jul 15 Javascript
js实现div拖动动画运行轨迹效果代码分享
Aug 27 Javascript
js 判断附件后缀的简单实现方法
Oct 11 Javascript
el表达式 写入bootstrap表格数据页面的实例代码
Jan 11 Javascript
JS数组搜索之折半搜索实现方法分析
Mar 27 Javascript
Vue开发中整合axios的文件整理
Apr 29 Javascript
js中let和var定义变量的区别
Feb 08 Javascript
vue实现PC端录音功能的实例代码
Jun 05 Javascript
记录一次websocket封装的过程
Nov 23 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
PHP 获取目录下的图片并随机显示的代码
2009/12/28 PHP
php+mysql事务rollback&amp;commit示例
2010/02/08 PHP
Admin generator, filters and I18n
2011/10/06 PHP
php查看网页源代码的方法
2015/03/13 PHP
PHP浮点数的一个常见问题
2016/03/10 PHP
PHP使用imagick扩展实现合并图像的方法
2017/04/25 PHP
PHP实现的微信APP支付功能示例【基于TP5框架】
2019/09/16 PHP
工作需要写的一个js拖拽组件
2011/07/28 Javascript
javascript学习笔记(十三) js闭包介绍(转)
2012/06/20 Javascript
javascript实现复选框超过限制即弹出警告框的方法
2015/02/25 Javascript
浅谈JS原生Ajax,GET和POST
2016/06/08 Javascript
javascript滚轮控制模拟滚动条
2016/10/19 Javascript
JavaScript对象引用与赋值实例详解
2017/03/15 Javascript
解决webpack打包速度慢的解决办法汇总
2017/07/06 Javascript
vue发送ajax请求详解
2018/10/09 Javascript
微信小程序开发之点击按钮退出小程序的实现方法
2019/04/26 Javascript
微信小程序 子级页面返回父级并把子级参数带回父级实现方法
2019/08/22 Javascript
js实现盒子移动动画效果
2020/08/09 Javascript
python将字符串转换成数组的方法
2015/04/29 Python
在Python的Django框架中用流响应生成CSV文件的教程
2015/05/02 Python
Python中的TCP socket写法示例
2018/05/11 Python
在windows下Python打印彩色字体的方法
2018/05/15 Python
Python3实现的简单工资管理系统示例
2019/03/12 Python
python求numpy中array按列非零元素的平均值案例
2020/06/08 Python
Python+Opencv身份证号码区域提取及识别实现
2020/08/25 Python
python装饰器实现对异常代码出现进行自动监控的实现方法
2020/09/15 Python
德国baby-markt婴儿用品瑞士网站:baby-markt.ch
2017/06/09 全球购物
泰国办公用品购物网站:OfficeMate
2018/02/04 全球购物
什么是聚集索引和非聚集索引
2012/01/17 面试题
汽车销售顾问求职自荐信
2014/01/01 职场文书
卖房协议书
2014/04/11 职场文书
《狼和小羊》教学反思
2014/04/20 职场文书
师德标兵先进事迹材料
2014/12/19 职场文书
导游词之北京明十三陵
2019/10/28 职场文书
Python pyecharts绘制条形图详解
2022/04/02 Python
GTX1650super好不好 gtx1650super显卡属于什么级别
2022/04/08 数码科技