Angular JS $q 学习备注

AngularJS $q是一个帮助处理异步执行函数的服务,当服务完成时使用它们的返回值(或异常)。


Deferred Api

一个被$q.defer()调用的deferred的新实例。
deferred对象的目的是暴露相关承诺实例,以及APIs被执行的成功或不成功情况,以及任务的状态。

方法:

resolve(value):根据value以解决派生的promise。如果值是通过$q.reject构造的rejection对象,该promise将被拒绝。

reject(reason):根据reason以拒绝派生的promise。这相当通过$q.reject构造的rejection对象来解决。

notify(value):在promise被执行的过程中提供状态更新情况。这可能会被多次调用,在promise被解决或被调用之前。

属性:
promise:承诺,与这个延迟(deferred)相关的promise对象。


Promise Api

当一个deferred实例被创建时,一个promise实例也被创建,并可以通过deferred.promise得到该引用。promise对象的目的是当它完成后允许需要的地方获得延迟任务的结果。

方法:

then(successCallback,errorCallback,notifyCallback):
无论什么时候,promise是已经被解决或拒绝,只要结果可用,就会调用一个成功或错误的回调异步。回调函数带着一个参数被调用:解决的结果或拒绝的原因。此外,在承诺被解决或被拒绝之前,通知回调可能会被调用0次或多次用来提供一个指示进度。

catch(errorCallback):
promise.then(null,errorCallback)的快捷方式。

finally(callback,notifyCallback):
用于promise不论是被解决还是被拒绝后释放资源或做一些处理。


链式承诺

因为调用本次promise的方法将会返回一个新的诞生的promise,它很容易创建一个承诺链:

promiseB = promiseA.then(result=>{
    return result+1;
})

当一个承诺解决另一个承诺可能创建一个任何长度的链。它可能在链中的任何处暂停或推迟承诺。这使得它可以像$http的响应拦截这类强大的API。


如何理解$q,deferred?

假设有一个家具厂,而它有一个VIP客户 张先生。

有一天张先生需要一个豪华衣柜,于是,他打电话给家具厂说我需要一个衣柜,回头做好了给我送来,这个操作就叫$q.defer,也就是延期,因为这个衣柜不是现在要的,所以张先生这是在发起一个可延期的请求。

同时,家具厂给他留下了一个回执号,并对他说:我们做好了会给您送过去,放心吧。这叫做promise,也就是承诺。

这样,这个defer算是正式创建了,于是他把这件事记录在自己的日记上,并且同时记录了回执号,这叫做deferred,也就是已延期事件。

现在,张先生就不用再去想着这件事了,该做什么做什么,这就是“异步”的含义。

假设家具厂在一周后做完了这个衣柜,并如约送到了张先生家(包邮哦,亲),这就叫做deferred.resolve(衣柜),也就是“已解决”。而这时候张先生只要签收一下这个(衣柜)参数就行了,当然,这个“邮包”中也不一定只有衣柜,还可以包含别的东西,比如厂家宣传资料、产品名录等。整个过程中轻松愉快,谁也没等谁,没有浪费任何时间。

假设家具厂在评估后发现这个规格的衣柜我们做不了,那么它就需要deferred.reject(理由),也就是“拒绝”。拒绝没有时间限制,可以发生在给出承诺之后的任何时候,甚至可能发生在快做完的时候。而且拒绝时候的参数也不仅仅限于理由,还可以包含一个道歉信,违约金之类的,总之,你想给他什么就给他什么,如果你觉得不会惹恼客户,那么不给也没关系。

假设家具厂发现,自己正好有一个符合张先生要求的存货,它就可以用$q.when(现有衣柜)来把这个承诺给张先生,这件事就立即被解决了,皆大欢喜,张先生可不在乎你是从头做的还是现有的成品,只会惊叹于你们的效率之高。

假设这个家具厂对客户格外的细心,它还可能通过deferred.notify(进展情况)给张先生发送进展情况的“通知”。

这样,整个异步流程就圆满完成,无论成功或者失败,张先生都没有往里面投入任何额外的时间成本。

好,我们再扩展一下这个故事:

张先生这次需要做一个桌子,三把椅子,一张席梦思,但是他不希望今天收到个桌子,明天收到个椅子,后天又得签收一次席梦思,而是希望家具厂做好了之后一次性送过来,但是他下单的时候又是分别下单的,那么他就可以重新跟家具厂要一个包含上述三个承诺的新承诺,这就是$q.all(桌子承诺,椅子承诺,席梦思承诺),

这样,他就不用再关注以前的三个承诺了,直接等待这个新的承诺完成,到时候只要一次性签收了前面的这些承诺就行了。
function commonJsPromise() {
    var deferred = $q.defer();
    $timeout(function () {
        deferred.notify("commonJS notify");
        if (iWantResolve) {
            deferred.resolve("commonJS resolved");
        } else {
            deferred.reject("commonJS reject");
        }

    }, 500);

    return deferred.promise;
}

commonJsPromise()
    .then(function /** success callback**/(data) {
        console.log(data);

    }, function /** error callback **/ (err) {
        console.log(err);
    }, function /** progress callback **/ (update) {
        console.log(update);
    });

// if(iWantResolve == true) output: commonJS notify commonJS resolved
// if(iWantResolve = false) output: commonJS notify commonJS reject
$q.all
  • $q.all([promise1, promise1]) 接受一个包含若干个 promise 的数组
  • 等所有的 promise resolve 后, 其本身 resolve 包含上述结果的数组 [data1, data2]
  • 如果上述 promise 有一个 reject, 那么$q.all() 会把这个 rejected promise 作为其 rejected promise (只有一个哦)
  • progress/notify 的 callback 并没有用
$q.all([es6promise(), commonJsPromise()])
    .then(function (dataArr) {
        console.log("$q.all: ", dataArr);
    }, function (err) {
        console.log("$q.all: ", err)
    }, function /** unnecessary **/ (update) {
        console.log("$q.all", update);
    });
// if(iWantResolve == true) output: $q.all:  ["es6promise resolved", "commonJS resolved"]
// if(iWantResolve = false) output: $q.all:  es6promise reject
q.reject, q.when , $q.resolve
  • $q.reject() 立即返回一个rejected 的 promise, 在链式调用的时候很有用
  • q.resolve== q.when(value, successCb, errorCb, progressCb)
  • value 可能是一个 then-able 的 obj(即可以是 q.defer(),),, q.when 最终都会返回一个 promise
  • q.when, q.when(value).then(fn, fn, fn) 的形式
$q.reject("instant reject")
    .catch(function (err) {
        console.log(err);
    });
// output: instant reject

$q.when(commonJsPromise(),
    function /** success callback **/(data) {
        console.log("$q.when success callback function: " + data);
        return "$q.when success callback return another value";
    })
    .then(function (data) {
        console.log("$q.when then function:" + data);
    });

// if(iWantResolve == true) output: 
// $q.when success callback functionL: commonJS resolved
// $q.when then function:$q.when success callback return another value

// if(iWantResolve = false) output: 
// $q.when err callback function: commonJS reject
// $q.when then function:undefined

$q.when("some value", function (data){
    console.log(data);
})

// output: some value

任何在successCb,errCb中返回的非$q.reject()对象,都将成为一个resolve的promise。所有可以出现promise.then().then().then()的语法。

$q.when("1")
    .then(function (data) {
        console.log(data);
        return $q.reject(2);
    })
    .catch(function (err) {
        console.log(err);
        return 3;
    })
    .then(function (data) {
        console.log(data);
    })

// output: 1 2 3 

原文章地址:

https://segmentfault.com/a/1190000004317947
http://www.angularjs.net.cn/api/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值