资讯专栏INFORMATION COLUMN

Angular $q 完全指南

U2FsdGVkX1x / 3177人阅读

摘要:假设家具厂在一周后做完了这个衣柜,并如约送到了张先生家包邮哦,亲,这就叫做衣柜,也就是已解决。这样,整个异步流程就圆满完成,无论成功或者失败,张先生都没有往里面投入任何额外的时间成本。

如果想使用 $http 或者其他异步操作, 那 $q 是必须要掌握的概念啦. Let"s get started!

如何理解$q, deferred object ?

形象的讲解angular中的$q与promise

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

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

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

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

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

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

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

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

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

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

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

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

这样,他就不用再关注以前的三个承诺了,直接等待这个新的承诺完成,到时候只要一次性签收了前面的这些承诺就行了。

如何创建 promise -1

$q 支持两种写法, 第一种是类似于ES6标准构造函数写法

$q(function resolver (resolve, reject) {})

注意:

+ ES6 写法并不支持 progress/notify 的回调函数
+ 在构造函数中抛异常也并不会显式的reject the promise
// var iWantResolve = false;
var iWantResolve = true;

function es6promise() {
    return $q(function (resolve, reject) {
        $timeout(function () {
            if (iWantResolve) {
                resolve("es6promise resolved");
            } else {
                reject("es6promise reject");
            }
        }, 1000)
    })
}
promise 的方法

promise.then(successCb, errCb, notifyCb)

其中successCb 将在 promise resolve 后被调用, errCb 将在 promise reject 后被调

notifyCb 将在 deferred.notify 后被调用, 可以多次调用

promise.catch == promise.then(null, errCb), 用于处理之前没有被处理的 rejected promise

promise.finally 将最后被调用, 一般用于资源释放的清理操作

es6promise()
    .then(function (data) {
        console.log(data);
    })
    .catch(function (err) {
        console.log(err);
    });

// if(iWantResolve == true) output: es6promise resolved
// if(iWantResolve = false) output: es6promise reject
如何创建 promise -2

第二种是类似于 commonJS 的写法 $q.deferred()

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
promise chains 链式调用

任何在 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 
参考资料

AngularJS Documentation for $q

形象的讲解angular中的$q与promise

Angular Promise Chaining Explained

$q.when() Is The Missing $q.resolve() Method In AngularJS

How does Angular $q.when work?

$q.when(promise) calls resolve() instead of reject()

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/91589.html

相关文章

  • 写给想做前端的你

    摘要:不过细想想,我邮只有前端的选修课啥的,课程也不是那么就业导向。至少目前,很少有大公司完全把作为前后端通用的技术栈。不能把简单看做是在服务端的延展。编译这个思想在前端领域很重要不改变现有的语言环境同时进行最佳的工程实践。 P.S. 喷神请绕道,大神勿喷,不引战,不攻击,不钻牛角尖。 大二时第一次接触前端。许多同学估计都想过要做一个网站,大部分又是从PHP开始的(谁让它是世界上最好的语言呢...

    JerryWangSAP 评论0 收藏0
  • 譯文 別再用 JS 框架了

    摘要:我承认从搞笑文章你糟蹋了中得到了一点灵感,不过我要再次说明,我无意嘲笑框架作者。库很好啊,我希望看到大家一致赞同远离的是框架。 原文《No more JS frameworks》 中文版翻译:老码农 翻译版: 日语 JS 框架看上去就像死亡和纳税,必然发生,无法避免。如果我能变成一只苍蝇趴在墙上,我就能确定每次启动一个新项目的时候,他们讨论的第一个问题肯定是:我们要用哪个 JS ...

    leejan97 评论0 收藏0
  • 1月份前端资源分享

    摘要:更多资源请文章转自月份前端资源分享视频前端技术论坛融合不可错过的迷你库测试框架实例教程为你详细解读请求头的具体含意解析的库如果要用前端框架,开发流程是怎样的与有什么区别正确使用的方法是什么流程图插件小如何让元素只能输入纯文本前端技术中 更多资源请Star:https://github.com/maidishike... 文章转自:https://github.com/jsfront...

    solocoder 评论0 收藏0
  • 2月份前端资源分享

    摘要:月份前端资源分享更多资源请文章转自前端生成好看的二维码十大经典排序算法带动图演示为什么知乎前端圈普遍认为游戏和展示的个人整理和封装的库中文详细注释供新手学习使用扩展语法记录掉坑初期工具汉字拼音转换工具实现汉字转拼音的插件下拉列表支持拼音简 2月份前端资源分享 更多资源请Star:https://github.com/maidishike... 文章转自:https://github...

    yanwei 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<