angular中的$q小结

近日,公司小伙伴把angular的$q服务,运用的炉火纯青,登峰造极,遂对之做个小结。

名词解释:

resolveHandler:then方法的第一个参数

rejectHandler:then方法的第二个参数或catch方法的第一个参数(catch方法即为then(null, function)的简写)

先来个基本用法:

1
2
3
4
5
6
7
8
var p = $q(function (resolve, reject) {
setTimeout(function () {
resolve('success');
}, 100)
});
p.then(function (data) {
console.log('then1:', data);
});

结果会输出

1
then1:success

这应该很好理解。

然后再来一个:

1
2
3
4
5
6
7
8
9
10
11
12
13
var p = $q(function (resolve, reject) {
setTimeout(function () {
resolve('success');
}, 100)
});
p.then(function (data) {
console.log('then1:', data);
});
p.then(function (data) {
console.log('then2:', data);
});

结果会输出:

1
2
then1: success
then2: success

再看这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
var p = $q(function (resolve, reject) {
setTimeout(function () {
resolve('success');
}, 100)
});
p.then(function (data) {
console.log('then1:', data);
return 'haha'
})
.then(function (data) {
console.log('then2:', data);
});

结果却是:

1
2
then1: success
then2: haha

两者非常相似,结果却不一致,为什么呢?

前者属于『分发式』调用(我自己YY的),『分发』后的resolveHandler的入参是分发者的返回值,即

后者这种属于链式调用,后一个then的resolveHandler的入参就是上一个then的resolveHandler的返回值, 即

再看:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var p = $q(function (resolve, reject) {
setTimeout(function () {
resolve('success');
}, 20)
});
p.then(function (data) {
console.log('then1:', data);
return 'haha'
})
.then(function (data) {
console.log('then2:', data);
return $q.resolve('xixi');
})
.then(function (data) {
console.log('then3:', data);
return $q(function (resolve, reject) {
setTimeout(function () {
resolve('success again')
},20)
})
})
.then(function (data) {
console.log('then4:', data);
})

输出结果为:

1
2
3
4
then1: success
then2: haha
then3: xixi
then4: success again

如果上一个then的resolveHandler返回的是一个promise对象,那么下一个then的resolveHandler的入参为这个promise对象resolve的值.

为了印证上述结论,再看一个更复杂的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var getPromise = function (resolveValue) {
return $q(function (resolve, reject) {
setTimeout(function () {
resolve(resolveValue);
},20)
})
};
getPromise('p1')
.then(function (data) {
console.log('then1:', data);
return 'haha'
})
.then(function (data) {
console.log('then2:', data);
return $q.resolve('xixi');
})
.then(function (data) {
console.log('then3:', data);
return getPromise('p2').then(function (data) {
console.log('then4:', data);
return getPromise('p3');
})
})
.then(function (data) {
console.log('then5:', data);
})

输出结果为:

1
2
3
4
5
then1: p1
then2: haha
then3: xixi
then4 p2
then5: p3

OK,上述都是resolve的情况,下面看看reject的情况。

来一个基本的:

1
2
3
4
5
6
7
8
9
10
$q(function (resolve, reject) {
setTimeout(function () {
reject('failed');
}, 20)
})
.then(function (data) {
console.log('success1:', data);
},function (data) {
console.log('fail1:', data);
});

结果输出:

1
fail1: failed

应该很好理解。

来看一个复杂的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$q(function (resolve, reject) {
setTimeout(function () {
reject('failed');
}, 20)
})
.then(function (data) {
console.log('success1:', data);
})
.then(function (data) {
console.log('success2:', data);
},function (data) {
console.log('fail2:', data);
return 'fffff';
})
.then(function (data) {
console.log('success3:', data);
return $q.reject('reject 3');
}, function (data) {
console.log('fail3:', data);
})
.then(function (data) {
console.log('success4:', data);
})
.catch(function (data) {
console.log(data);
});

输出结果为:

1
2
3
fail2: failed
success3: fffff
reject 3

promise被reject后,第一个rejectHandler将接受到reject的值,但是这个rejectHandler返回的值就此『迷途知返』,传给接下来的resolveHandler。如果返回的是将被reject的promise对象,被reject的值才会被传递给下一个rejectHandler。

 

总结

似乎讲的并不是那么清楚,请读者仔细推敲代码的运行结果,可以更加深刻理解$q的用法,用于处理复杂异步逻辑非常合适。本文没有涉及$q的所有API,而且promise规范也不仅仅只有一种,请读者自行延伸查阅。