翻譯:瘋狂的技術(shù)宅?
http://2ality.com/2018/04/extracting-loops.html
在本文中溜嗜,我們將介紹兩種提取循環(huán)內(nèi)數(shù)據(jù)的方法:內(nèi)部迭代和外部迭代。
循環(huán)
舉個(gè)例子器瘪,假設(shè)有一個(gè)函數(shù)?logFiles():
1constfs?=require('fs');
2constpath?=require('path');
3
4functionlogFiles(dir){
5for(constfileNameoffs.readdirSync(dir))?{//?(A)
6constfilePath?=?path.resolve(dir,?fileName);
7console.log(filePath);
8conststats?=?fs.statSync(filePath);
9if(stats.isDirectory())?{
10logFiles(filePath);//?(B)
11}
12}
13}
14logFiles(process.argv[2]);
從 A 行開始的循環(huán)用來記錄文件路徑流强。它是?for-of?循環(huán)和遞歸的組合(遞歸調(diào)用在 B 行)脑慧。
如果你發(fā)現(xiàn)循環(huán)內(nèi)的某些數(shù)據(jù)(迭代文件)有用抡驼,但又不想記錄它阳藻,那應(yīng)該怎么辦晰奖?
內(nèi)部迭代
提取循環(huán)內(nèi)數(shù)據(jù)的第一個(gè)方法是內(nèi)部迭代:
1constfs?=require('fs');
2constpath?=require('path');
3
4functionlogFiles(dir,?callback){
5for(constfileNameoffs.readdirSync(dir))?{
6constfilePath?=?path.resolve(dir,?fileName);
7callback(filePath);//?(A)
8conststats?=?fs.statSync(filePath);
9if(stats.isDirectory())?{
10logFiles(filePath,?callback);
11}
12}
13}
14logFiles(process.argv[2],?p?=>console.log(p));
這種迭代方式與Array的?.forEach()類似:logFiles()?內(nèi)實(shí)現(xiàn)循環(huán)并對(duì)每個(gè)迭代值(行A)調(diào)用?callback。
外部迭代
內(nèi)部迭代的替代方案是外部迭代:我們實(shí)現(xiàn)了一個(gè)iterable腥泥,可以用生成器幫助我們實(shí)現(xiàn):
1constfs?=require('fs');
2constpath?=require('path');
3
4function*logFiles(dir){
5for(constfileNameoffs.readdirSync(dir))?{
6constfilePath?=?path.resolve(dir,?fileName);
7yieldfilePath;
8conststats?=?fs.statSync(filePath);
9if(stats.isDirectory())?{
10yield*?logFiles(filePath);//?(A)
11}
12}
13}
14for(constpoflogFiles(process.argv[2]))?{
15console.log(p);
16}
如果是內(nèi)部迭代匾南,logFiles()?會(huì)調(diào)用我們(“推”給我們)。而這一次蛔外,換我們來調(diào)用它了(“拉”過來)蛆楞。
請(qǐng)注意,在生成器中夹厌,必須通過?yield*?進(jìn)行遞歸調(diào)用(第A行):如果只調(diào)用?logFiles()?那么它會(huì)返回一個(gè)iterable豹爹。但我們想要的是在該 iterable 中?yield?每個(gè)項(xiàng)目。這就是?yield*?的作用矛纹。
生成器有一個(gè)非常好的特性臂聋,就是處理過程能夠與內(nèi)部迭代一樣互鎖:每當(dāng)?logFiles()?創(chuàng)建另一個(gè)filePath?時(shí),我們能夠立即查看它或南,然后?logFiles()?繼續(xù)孩等。這是一種簡(jiǎn)單的協(xié)作式多任務(wù)處理,其中?yield?暫停當(dāng)前任務(wù)并切換到另一個(gè)任務(wù)采够。
擴(kuò)展閱讀
Chapter “Iterables and iterators” in “Exploring ES6”.【http://exploringjs.com/es6/ch_iteration.html】
Chapter “Generators” in “Exploring ES6”. 【http://exploringjs.com/es6/ch_generators.html】