详解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 相关文章推荐
JavaScript 在网页上单击鼠标的地方显示层及关闭层
Dec 30 Javascript
jquery validation验证身份证号,护照,电话号码,email(实例代码)
Nov 06 Javascript
推荐一个封装好的getElementsByClassName方法
Dec 02 Javascript
微信JSSDK上传图片
Aug 23 Javascript
js实现简洁的TAB滑动门效果代码
Sep 06 Javascript
学习javascript面向对象 javascript实现继承的方式
Jan 04 Javascript
javascript中错误使用var造成undefined
Mar 31 Javascript
json传值以及ajax接收详解
May 24 Javascript
Bootstrap 模态对话框只加载一次 remote 数据的完美解决办法
Jul 09 Javascript
bootstrap自定义样式之bootstrap实现侧边导航栏功能
Sep 10 Javascript
简单了解vue.js数组的常用操作
Jun 17 Javascript
使用layui的router来进行传参的实现方法
Sep 06 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
thinkphp3.2实现在线留言提交验证码功能
2017/07/19 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
PHP中使用mpdf 导出PDF文件的实现方法
2018/10/22 PHP
javascript中如何处理引号编码&amp;#034;
2013/08/15 Javascript
JS实现点击图片在当前页面放大并可关闭的漂亮效果
2013/10/18 Javascript
JS 仿腾讯发表微博的效果代码
2013/12/25 Javascript
js实时获取并显示当前时间的方法
2015/07/31 Javascript
js调用百度地图及调用百度地图的搜索功能
2015/09/07 Javascript
基于Jquery制作图片文字排版预览效果附源码下载
2015/11/18 Javascript
极易被忽视的javascript面试题七问七答
2016/02/15 Javascript
javascript 解决浏览器不支持的问题
2016/09/24 Javascript
angularjs实现多张图片上传并预览功能
2017/02/24 Javascript
nodejs服务搭建教程 nodejs访问本地站点文件
2017/04/07 NodeJs
详解AngularJs HTTP响应拦截器实现登陆、权限校验
2017/04/11 Javascript
浅析Javascript中双等号(==)隐性转换机制
2017/10/27 Javascript
bootstrap table sum总数量统计实现方法
2017/10/29 Javascript
Angular之toDoList的实现代码示例
2017/12/02 Javascript
Vue + better-scroll 实现移动端字母索引导航功能
2018/05/07 Javascript
jQuery事件绑定和解绑、事件冒泡与阻止事件冒泡及弹出应用示例
2019/05/13 jQuery
原生js实现的金山打字小游戏(实例代码详解)
2020/03/16 Javascript
Vue自定义render统一项目组弹框功能
2020/06/07 Javascript
JavaScript实现简单验证码
2020/08/24 Javascript
python中bisect模块用法实例
2014/09/25 Python
利用Python绘制数据的瀑布图的教程
2015/04/07 Python
浅析python继承与多重继承
2018/09/13 Python
Python将json文件写入ES数据库的方法
2019/04/10 Python
python tkinter canvas 显示图片的示例
2019/06/13 Python
centos7之Python3.74安装教程
2019/08/15 Python
python 实现&quot;神经衰弱&quot;翻牌游戏
2020/11/09 Python
Django haystack实现全文搜索代码示例
2020/11/28 Python
全国道德模范事迹
2014/02/01 职场文书
2014幼儿园教师个人工作总结
2014/11/08 职场文书
行政人事主管岗位职责
2015/04/11 职场文书
党员进社区活动总结
2015/05/07 职场文书
2016年教师学习教师法心得体会
2016/01/20 职场文书
Redis Cluster 字段模糊匹配及删除
2021/05/27 Redis