什么是$q

$q是angularjs1.x中内置服务,在需要使用时可以注入它。

angular.module('app').controller('myController', function myController($q){
    // further operation..
});

 

为什么使用$q

$q的使用目的是为了提供更好的异步编程解决方案。

 


 

来看看$q的api:

$q.defer()

$q.defer执行时返回一个延迟对象(defer)。延迟对象有三种状态: resolve(解决), reject(拒绝), notify(通知)。

同时这三种状态在defer对象下各有一个同名方法,用于改变defer对象的状态值。

一旦状态更改成resolve或reject了,就无法改回来了,这点要注意。

同时,在执行defer.resolve(), defer.reject(), defer.notify()时,可以传入一个参数,这个参数将成为

对应回调函数的参数。看个例子

var defer = $q.defer();
var myPic = new Image();

myPic.onload = function(){
  defer.resolve(myPic);
}

myPic.onerror = function(){
  defer.reject();
}

defer.promise.then(function(img){
  console.log('download complete');
  // 这里可以对参数img进行操作
}, function(reason){
  console.log('network error');
});

myPic.src = '/somefile/someimage';

这个例子中,对image的加载做了一些封装。

当图片加载完成或加载失败,会在控制台输出一些提示。

可能在这个例子中,$q发挥的作用并不大,但是放到一些特殊的场景,

它将发挥奇效。

 

promise

promise(承诺)对象是defer下的属性,它有一些方法处理回调函数,当defer对象的状态变更时,

promise会执行相应的回调。

 

promise.then(resolveCallback, rejectCallback, notifyCallback)

then方法的三种回调分别对应promise的三种状态的处理。

返回一个promise。也就是说,then方法可以应用链式写法。

注意的是,前面then方法中的resolveCallback的返回值,将会成为后面then方法的resolveCallback的参数。(其他同理)

angular.module('app').controller('myController', function myController($q){
    var defer1 = $q.defer();

    defer1.promise.then(function resolveCallback(result){
        console.log('resolve callback: ' + result);
    }, function rejectCallback(reason){
        console.log('reject回调不会执行');
    }, function notifyCallback(message){
        console.log('notify callback: ' + message);
    });

    defer1.notify('promise got message');
    defer1.resolve('promise resolve');   
});

// notify callback: promise got message
// resolve callback: promise resolve

nofity不限制调用次数(应用于进度更改通知);

 

promise.catch(rejectCallback)

catch方法是then方法的一个语法糖,相当于promise.then(null, rejectCallback)。

 

promise.finally(callback)

在一些旧浏览器,finally是保留字,你可能要这么调用它: promise['finally'](callback)。

 

$q.reject(value)

返回一个promise。该promise的状态是reject。

也就是说,返回值会马上执行链式操作中的reject的处理方法,如:

$q.reject(reason).then(function(result){
  console.log('this would never implement');
}, function(reason){
  console.log('promise reject! reason: ' + reason);
});

// or

$q.reject(reason).catch(function(reason){
  console.log('reject reason: ' + reason);
});

 

 

$q.when(value)

when方法用于封装一个可能是defer对象的值。返回一个promise对象。

如果输入值是promise时,将返回一个promise,当它状态改变时执行后续的链式操作。

如果输入的是一个普通值,也返回一个promise,并且该promise的状态是resolve。换句话说,后面的链式操作会马上跑起来。

你也可以理解为$q.when 和 $q.reject 是一对对应的方法。

 

$q.all(promises)

all方法用于将多个promise绑定称为单个的promise。

它接受一个promise数组作为参数,返回一个promise对象。

当所有的promise都变成resolve状态时,才会执行回调。