Node.js 如何使用异步回调进行迭代?
Node.js how to iterate with async callback?
我正在做的是使用 fs 将 5 个 html 页部分 (html, head, chead, topaside, main, footer
) 拼接在一起。文件名为htmlpage.js
,所以你可以在命令行工具中直接运行 node htmlpage.js file1 file2 file3 ...
,它会将html页的部分拼接在一起,然后吐出[=18] =].我不喜欢使用模板 engine/library/framework 或其他任何东西,尤其是在我学习的时候。
这是源代码:
'use strict';
const fs = require('fs'),
head = fs.createReadStream('./html-parts/head.html', 'utf8'),
topaside = fs.createReadStream('./html-parts/topaside.html', 'utf8'),
footer = fs.createReadStream('./html-parts/footer.html', 'utf8');
let name = process.argv.slice(2),
htmlray = [],
ni = 0,
nl = name.length;
for (ni; ni < nl; ni ++) {
let cheadP = './html-parts/' + name[ni] + '-head.html',
mainP = './html-parts/' + name[ni] + '-main.html',
htmlP = name[ni] + '.html',
chead = fs.createReadStream(cheadP, 'utf8'),
main = fs.createReadStream(mainP, 'utf8'),
html = fs.createWriteStream(htmlP, 'utf8');
//let those parts form an array
htmlray = [html, head, chead, topaside, main, footer];
openendPipe(htmlray[1], htmlray[0]);
htmlray[1].on('end', () => {
openendPipe(htmlray[2], htmlray[0]);
htmlray[2].on('end', () => {
openendPipe(htmlray[3], htmlray[0]);
htmlray[3].on('end', () => {
openendPipe(htmlray[4], htmlray[0]);
htmlray[4].on('end', () => {
htmlray[5].pipe(htmlray[0]);
htmlray[5].on('end', () => {
console.log(name + '.html' + ' created');
});
});
});
});
});
}
function openendPipe(src, dst) {
return src.pipe(dst, {end: false});
}
但是如果 htmlray
有 100 个部分,我希望能够进行一次迭代来替换这些代码,我们称之为 pipeblock
:
openendPipe(htmlray[1], htmlray[0]);
htmlray[1].on('end', () => {
openendPipe(htmlray[2], htmlray[0]);
htmlray[2].on('end', () => {
openendPipe(htmlray[3], htmlray[0]);
htmlray[3].on('end', () => {
openendPipe(htmlray[4], htmlray[0]);
htmlray[4].on('end', () => {
htmlray[5].pipe(htmlray[0]);
htmlray[5].on('end', () => {
console.log(name + '.html' + ' created');
});
});
});
});
});
我尝试了这些解决方案,它们没有用:
解决方案 1:
(function () {
let i = 0, count = 1;
function nextpipe() {
let arr = arguments[0];
i ++;
if (count > 5) return;
openendPipe(arr[i], arr[0]);
count ++;
arr[i].on('end', nextpipe);
}
return nextpipe;
})();
//then replace 'pipeblock' with 'nextpipe(htmlray)';
//console.log: nextpipe is undefined.
解决方案 2:
//replace 'pipeblock' with these code
let pi = 1,
pl = htmlray.length - 1;
htmlray[pi].pipe(htmlray[0], {end: false});
htmlray[pi].on('end', nextpipe);
function nextpipe() {
if (pi > pl) return console.log(name + '.html' + ' created');;
pi ++;
htmlray[pi].pipe(htmlray[0], {end: false});
htmlray[pi].on('end', nextpipe);
}
//cosole.log:
//htmlray[pi].pipe(htmlray[0], {end: false});
//TypeError: Cannot read property 'pipe' of undefined
这个东西调用 "callback hell",你应该使用一些库来处理异步调用,比如 async.js
或者(更好)使用 promises。
只需像这样简单地承诺 fs.readFile
(或者为 fs.createReadStream
编写您自己的承诺,如果您想使用它)
const readFile = Promise.promisify(require('fs').readFile);
然后使用 Promise.all()
组合您的请求承诺
这里是 http://bluebirdjs.com/docs/api/promise.promisify.html
、http://bluebirdjs.com/docs/api/promise.all.html
的示例,fs
用于 Bluebird promise 库。
当我阅读 async 和 promise 文档时,我谈到了有关并行、系列和瀑布的部分。我的问题是关于创建一个 html 页面,所以它不能并行完成。但是文档开始并谈论了很多关于并行的内容,它们只会让我更加困惑。掌握所有这些可能需要很长时间。无论如何,在我进行试验的同时,我想出了一个简单的解决方案。
在我的问题中,重复的部分是关于检查前面的html部分是否已经使用readingStream.on('end', <do next writing>);
写完了,所以我把它做成一个函数:
function ifend(src, src2, dst) {
return src.on('end', () => {return openendPipe(src2, dst);});
}
然后我可以把pipeblock
变成:
openendPipe(htmlray[0], html);
ifend(htmlray[0], htmlray[1], html);
ifend(htmlray[1], htmlray[2], html);
ifend(htmlray[2], htmlray[3], html);
ifend(htmlray[3], htmlray[4], html);
然后我可以在函数中进行迭代:
function createHtml(src, dst) {
let l = src.length - 1,
i = 0;
openendPipe(src[0], dst);
for (i; i < l; i ++) {
//iterate ifend function.
ifend(src[i], src[i + 1], dst);
}
return dst;
}
现在我可以用这个替换pipeblock
:
createHtml(htmlray, html);
我正在做的是使用 fs 将 5 个 html 页部分 (html, head, chead, topaside, main, footer
) 拼接在一起。文件名为htmlpage.js
,所以你可以在命令行工具中直接运行 node htmlpage.js file1 file2 file3 ...
,它会将html页的部分拼接在一起,然后吐出[=18] =].我不喜欢使用模板 engine/library/framework 或其他任何东西,尤其是在我学习的时候。
这是源代码:
'use strict';
const fs = require('fs'),
head = fs.createReadStream('./html-parts/head.html', 'utf8'),
topaside = fs.createReadStream('./html-parts/topaside.html', 'utf8'),
footer = fs.createReadStream('./html-parts/footer.html', 'utf8');
let name = process.argv.slice(2),
htmlray = [],
ni = 0,
nl = name.length;
for (ni; ni < nl; ni ++) {
let cheadP = './html-parts/' + name[ni] + '-head.html',
mainP = './html-parts/' + name[ni] + '-main.html',
htmlP = name[ni] + '.html',
chead = fs.createReadStream(cheadP, 'utf8'),
main = fs.createReadStream(mainP, 'utf8'),
html = fs.createWriteStream(htmlP, 'utf8');
//let those parts form an array
htmlray = [html, head, chead, topaside, main, footer];
openendPipe(htmlray[1], htmlray[0]);
htmlray[1].on('end', () => {
openendPipe(htmlray[2], htmlray[0]);
htmlray[2].on('end', () => {
openendPipe(htmlray[3], htmlray[0]);
htmlray[3].on('end', () => {
openendPipe(htmlray[4], htmlray[0]);
htmlray[4].on('end', () => {
htmlray[5].pipe(htmlray[0]);
htmlray[5].on('end', () => {
console.log(name + '.html' + ' created');
});
});
});
});
});
}
function openendPipe(src, dst) {
return src.pipe(dst, {end: false});
}
但是如果 htmlray
有 100 个部分,我希望能够进行一次迭代来替换这些代码,我们称之为 pipeblock
:
openendPipe(htmlray[1], htmlray[0]);
htmlray[1].on('end', () => {
openendPipe(htmlray[2], htmlray[0]);
htmlray[2].on('end', () => {
openendPipe(htmlray[3], htmlray[0]);
htmlray[3].on('end', () => {
openendPipe(htmlray[4], htmlray[0]);
htmlray[4].on('end', () => {
htmlray[5].pipe(htmlray[0]);
htmlray[5].on('end', () => {
console.log(name + '.html' + ' created');
});
});
});
});
});
我尝试了这些解决方案,它们没有用:
解决方案 1:
(function () {
let i = 0, count = 1;
function nextpipe() {
let arr = arguments[0];
i ++;
if (count > 5) return;
openendPipe(arr[i], arr[0]);
count ++;
arr[i].on('end', nextpipe);
}
return nextpipe;
})();
//then replace 'pipeblock' with 'nextpipe(htmlray)';
//console.log: nextpipe is undefined.
解决方案 2:
//replace 'pipeblock' with these code
let pi = 1,
pl = htmlray.length - 1;
htmlray[pi].pipe(htmlray[0], {end: false});
htmlray[pi].on('end', nextpipe);
function nextpipe() {
if (pi > pl) return console.log(name + '.html' + ' created');;
pi ++;
htmlray[pi].pipe(htmlray[0], {end: false});
htmlray[pi].on('end', nextpipe);
}
//cosole.log:
//htmlray[pi].pipe(htmlray[0], {end: false});
//TypeError: Cannot read property 'pipe' of undefined
这个东西调用 "callback hell",你应该使用一些库来处理异步调用,比如 async.js
或者(更好)使用 promises。
只需像这样简单地承诺 fs.readFile
(或者为 fs.createReadStream
编写您自己的承诺,如果您想使用它)
const readFile = Promise.promisify(require('fs').readFile);
然后使用 Promise.all()
这里是 http://bluebirdjs.com/docs/api/promise.promisify.html
、http://bluebirdjs.com/docs/api/promise.all.html
的示例,fs
用于 Bluebird promise 库。
当我阅读 async 和 promise 文档时,我谈到了有关并行、系列和瀑布的部分。我的问题是关于创建一个 html 页面,所以它不能并行完成。但是文档开始并谈论了很多关于并行的内容,它们只会让我更加困惑。掌握所有这些可能需要很长时间。无论如何,在我进行试验的同时,我想出了一个简单的解决方案。
在我的问题中,重复的部分是关于检查前面的html部分是否已经使用readingStream.on('end', <do next writing>);
写完了,所以我把它做成一个函数:
function ifend(src, src2, dst) {
return src.on('end', () => {return openendPipe(src2, dst);});
}
然后我可以把pipeblock
变成:
openendPipe(htmlray[0], html);
ifend(htmlray[0], htmlray[1], html);
ifend(htmlray[1], htmlray[2], html);
ifend(htmlray[2], htmlray[3], html);
ifend(htmlray[3], htmlray[4], html);
然后我可以在函数中进行迭代:
function createHtml(src, dst) {
let l = src.length - 1,
i = 0;
openendPipe(src[0], dst);
for (i; i < l; i ++) {
//iterate ifend function.
ifend(src[i], src[i + 1], dst);
}
return dst;
}
现在我可以用这个替换pipeblock
:
createHtml(htmlray, html);