Javascript异步流程控制之Promise(1)-Angular $q简介

来源:互联网 发布:百度开放大数据 编辑:程序博客网 时间:2024/04/30 19:46

Javascript异步流程控制之Promise(1)-Angular $q简介

原文写于 2015-01-25 https://github.com/kuitos/kuitos.github.io/issues/15

先来说说什么是Promise吧

Promise是抽象异步处理对象以及对其进行各种操作的组件。 其详细内容在接下来我们还会学到,Promise并不是从JavaScript中发现的概念。
Promise最初被发现是在 E言語中, 它是基于并列/并行处理设计的一种编程语言。

简言之,Promise就是用于改善异步编程体验的一种编程模型,它提供一系列的api和方法论,让你能更优雅的解决异步编程中出现的一些问题。目前很多第三方框架或类库(如Angular和JQuery)都依照Promise/A+社区制定的规范做了相应的实现(JQuery基于历史原因很多地方与Promise规范不一致,so不建议通过JQuery源码学习Promise),最主要的是,Promise现在已经成为ES6的既定标准,目前部分高版本浏览器已原生支持Promise(后面有机会给出demo),所以我们还是很有必要来了解一下这到底是一个什么东西。

首先来看看,Promise的核心竞争力在哪

以前我们在处理一系列有依赖性的回调的时候,我们的代码是这样写的

step1(function (value1) {    step2(value1, function(value2) {        step3(value2, function(value3) {            step4(value3, function(value4) {                // Do something with value4            });        });    });});

是的,就是一层层的回调嵌套,传说中的回调地狱
那么如果我们换成Promise的方式来实现呢

step1().then(step2).then(step3).then(step4)

效果显而易见,代码简单逻辑清晰,异步的回调嵌套写法变成了同步(本质上当然还是异步的)的写法看上去是不是优雅多了

目前,Angular基于现在流行的NodeJs异步流程控制库Q实现了一个微缩版的Q,它提供了一些最常用的规范的Promise API,并对外提供了$q这样一个service,这里我们介绍一下angular框架中主要有哪些api及相应的使用场景。(声明一点,angular中所有的ajax请求均返回promise)

  1. Promise.then() 将回调嵌套变成链式调用。then可以接两个参数,sucessCallback 和 errorCallback,即then(successCb, errorCb)
  2. Deferred.resolve(val) 通知promise请求处理完毕,并将处理结果传给回调函数
  3. Deferred.reject(msg) 通知promise请求出现异常,将异常信息传给回调函数
  4. $q.when(val/fn) 将任意 对象/函数 包装成promise,返回包装好的promise
  5. $q.all(promises).then() 当所有promise都成功解析后流程才继续往下走
    使用场景

Promise.then()

// 通常,我们处理多层顺序依赖的异步调用,我们会这样去写$http.get().success(function (val1){    $http.get(val1).success(function (val2){        $http.get(val2).success(function (val3){            console.log(val3);        })    });});// 当用Promise来处理时,写法会变成这样function funcA(val1){    return $http.get(val1).suceess(function (val2){        return val2;       })}function funcB(val2){    return $http.get(val2).suceess(function (val3){        return val3;       })}function funcC(val3){    console.log(val3);}$http.get().then(funcA).then(funcB).then(funcC);// 很显然,使用了Promise方式代码可读性变的强很多

Deferred.resolve

// Deferred.resolve用于通知promise结果已经处理好,可以开始处理回调了// 假设我们有这样一个业务,按钮点击时的处理逻辑依赖于另一个函数异步返回的数据,就像这样var a;setTimeout(function(){    a = 10;},5000);dom.onclick = function(){    console.log(a);}// 我们总不能在onclick里轮询直到a被赋值吧。。// 有了Promise一切变得简单var defer = $q.defer(),    a;setTimeout(function (){    defer.resolve(10);},5000);dom.onclick = function(){    defer.promise.then(function(a){        console.log(a);    });}

Deferred.reject

// 用法同deferred.resolve,只不过它调用之后会走失败回调setTimeout(function(){    defer.reject(10);},5000);defer.promise.then(function successCb(a){    console.log(a+"success");}, function errorCb(a){    console.log(a+"error");});// 5秒后打出 "10error"

Promise.all

// 这个api就非常给力了,假设我们有这样一个场景// 页面上有A、B、C、D四块区域,其中A、B、C三块数据都是ajax获取的,D展示的数据需要综合A、B、C三个的数据// 难道我们得在 A 的请求回调里调用 B ,然后再B请求回调里调C这样一层层嵌套,直到所有请求准备好了再去处理D ?这样整个页面在同一时间只能有一个请求发出,效率太低// 可以这样写$q.all([promiseA,promiseB,promiseC]).then(funcD)// 这样页面在同一时间会发出三个请求,当所有请求都好了之后再去处理D页面,代码不仅变得更清晰而且效率更高最后介绍一下Promise.race([promises]),这个api angular并没有做实现,但是它已列入Promise/A+规范中,这里提一下Promise.race([promises])与Promise.all([promises])类似,只不过Promise.all是与集运算,而Promise.race()是或集运算,当promises中有一个被resolve了就会继续后面的then

Promise.race

// 当promiseA或promiseB其中有一个被resolve,则后面funcT会被执行// 使用场景有:进入一个页面时 当用户点击某个按钮或过5s 则展示某个提示,使用这个api会很方便Promise.race([promiseA,promiseB]).then(funcT);
0 0
原创粉丝点击