Skip to content

Commit 431937a

Browse files
author
andrew
committed
Add combine and end section
1 parent 08b432f commit 431937a

File tree

1 file changed

+134
-0
lines changed

1 file changed

+134
-0
lines changed

lesson17/README.md

+134
Original file line numberDiff line numberDiff line change
@@ -561,9 +561,143 @@ funcs.reduce(function(pre,current),Q(initialVal){
561561
回到我们一开始读取文件内容的例子。如果现在让我们把它改写成promise链,是不是很简单呢?
562562

563563
```js
564+
var Q = require('q'),
565+
fs = require('fs');
566+
function printFileContent(fileName) {
567+
return function(){
568+
var defer = Q.defer();
569+
fs.readFile(fileName,'utf8',function(err,data){
570+
if(!err && data) {
571+
console.log(data);
572+
defer.resolve();
573+
}
574+
})
575+
return defer.promise;
576+
}
577+
}
578+
//手动链接
579+
printFileContent('sample01.txt')()
580+
.then(printFileContent('sample02.txt'))
581+
.then(printFileContent('sample03.txt'))
582+
.then(printFileContent('sample04.txt'));
583+
```
584+
585+
很有成就感是不是。然而如果仔细分析,我们会发现为什么要他们顺序执行呢,如果他们能够并行执行不是更好吗? 我们只需要在他们都执行完成之后,得到他们的执行结果就可以了。
586+
587+
我们可以通过Q.all([promise1,promise2...])将多个promise组合成一个promise返回。
588+
注意:
589+
590+
1. 当all里面所有的promise都fulfil时,Q.all返回的promise状态变成fulfil
591+
2. 当任意一个promise被reject时,Q.all返回的promise状态立即变成reject
592+
593+
我们来把上面读取文件内容的例子改成并行执行吧
594+
595+
```js
596+
var Q = require('q'),
597+
fs = require('fs');
598+
/**
599+
*读取文件内容
600+
*@private
601+
*/
602+
function printFileContent(fileName) {
603+
//Todo: 这段代码不够简洁。可以使用Q.denodeify来简化
604+
var defer = Q.defer();
605+
fs.readFile(fileName,'utf8',function(err,data){
606+
if(!err && data) {
607+
console.log(data);
608+
defer.resolve(fileName + ' success ');
609+
}else {
610+
defer.reject(fileName + ' fail ');
611+
}
612+
})
613+
return defer.promise;
614+
}
615+
616+
Q.all([printFileContent('sample01.txt'),printFileContent('sample02.txt'),printFileContent('sample03.txt'),printFileContent('sample04.txt')])
617+
.then(function(success){
618+
console.log(success);
619+
});
620+
```
564621

622+
现在知道Q.all会在任意一个promise进入reject状态后立即进入reject状态。如果我们需要等到所有的promise都发生状态后(有的fulfil, 有的reject),再转换Q.all的状态, 这时我们可以使用Q.allSettled
623+
624+
```js
625+
var Q = require('q'),
626+
fs = require('fs');
627+
/**
628+
*读取文件内容
629+
*@private
630+
*/
631+
function printFileContent(fileName) {
632+
//Todo: 这段代码不够简洁。可以使用Q.denodeify来简化
633+
var defer = Q.defer();
634+
fs.readFile(fileName,'utf8',function(err,data){
635+
if(!err && data) {
636+
console.log(data);
637+
defer.resolve(fileName + ' success ');
638+
}else {
639+
defer.reject(fileName + ' fail ');
640+
}
641+
})
642+
return defer.promise;
643+
}
644+
645+
Q.allSettled([printFileContent('nosuchfile.txt'),printFileContent('sample02.txt'),printFileContent('sample03.txt'),printFileContent('sample04.txt')])
646+
.then(function(results){
647+
results.forEach(
648+
function(result) {
649+
console.log(result.state);
650+
}
651+
);
652+
});
565653
```
566654

655+
## 结束promise链
656+
657+
通常,对于一个promise链,有两种结束的方式。第一种方式是返回最后一个promise
658+
659+
如 return foo().then(bar);
660+
661+
第二种方式就是通过done来结束promise链
662+
663+
如 foo().then(bar).done()
664+
665+
为什么需要通过done来结束一个promise链呢? 如果在我们的链中有错误没有被处理,那么在一个正确结束的promise链中,这个没被处理的错误会通过异常抛出。
666+
667+
```js
668+
var Q = require('q');
669+
/**
670+
*@private
671+
*/
672+
function getPromise(msg,timeout,opt) {
673+
var defer = Q.defer();
674+
setTimeout(function(){
675+
console.log(msg);
676+
if(opt)
677+
defer.reject(msg);
678+
else
679+
defer.resolve(msg);
680+
},timeout);
681+
return defer.promise;
682+
}
683+
/**
684+
*没有用done()结束的promise链
685+
*由于getPromse('2',2000,'opt')返回rejected, getPromise('3',1000)就没有执行
686+
*然后这个异常并没有任何提醒,是一个潜在的bug
687+
*/
688+
getPromise('1',3000)
689+
.then(function(){return getPromise('2',2000,'opt')})
690+
.then(function(){return getPromise('3',1000)});
691+
/**
692+
*用done()结束的promise链
693+
*有异常抛出
694+
*/
695+
getPromise('1',3000)
696+
.then(function(){return getPromise('2',2000,'opt')})
697+
.then(function(){return getPromise('3',1000)})
698+
.done();
699+
700+
```
567701
这次我们要介绍的是 async 的 `mapLimit(arr, limit, iterator, callback)` 接口。另外,还有个常用的控制并发连接数的接口是 `queue(worker, concurrency)`,大家可以去 https://github.com/caolan/async#queueworker-concurrency 看看说明。
568702

569703
这回我就不带大家爬网站了,我们来专注知识点:并发连接数控制。

0 commit comments

Comments
 (0)