退出生成功能后如何清理。我遇到的问题是我使用Async Iterators第3阶段的EcmaScript提议从文件中读取了一些实用程序,我希望它在退出for-for循环后关闭它正在读取的文件。目前,由于此功能仅适用于第3阶段,因此要运行此功能,您必须使用babel进行转换。
使用以下代码,您可以看到问题。如果您输入一个输入文件,那么它将读取一行并打印出行阅读器仍处于打开状态。
我希望在返回迭代器时显式关闭LineReader
类中的文件。
我知道我可以通过不使用生成函数来执行此操作,而是按照概述here返回迭代器对象,但是有什么方法可以保留生成函数并为它定义返回方法。
的src /线reader.js
function deferred() {
const def = {}
def.promise = new Promise((resolve, reject) => {
def.resolve = resolve
def.reject = reject
})
return def
}
/**
* PromiseQueue from GTOR adapted for ES2015
* https://github.com/kriskowal/gtor
*/
class PromiseQueue {
constructor (values) {
this.ends = deferred();
if (values) {
values.forEach(this.put, this);
}
}
put(value) {
const next = deferred();
this.ends.resolve({
head: value,
tail: next.promise
});
this.ends.resolve = next.resolve;
}
get () {
var result = this.ends.promise.then(node=>node.head);
this.ends.promise = this.ends.promise.then(node=>node.tail)
return result;
};
}
class LineReader {
constructor (input, output) {
this.lineReader = require('readline').createInterface({ input, output });
this.lineQueue = new PromiseQueue();
this.isClosed = false;
this.lineReader.on('line', (line) => {
this.lineQueue.put(line);
this.lineReader.pause();
});
this.lineReader.on('close', (line) => {
this.isClosed = true;
this.lineQueue.put(Promise.resolve({done: true}));
});
this.lineReader.on('SIGCONT', () => {
// `prompt` will automatically resume the stream
this.lineReader.prompt();
});
}
readLine(){
var result = this.lineQueue.get().then(function (data) {
if(data && data.done) {
throw new Error("EOF");
}
return data
});
this.lineReader.resume();
return result;
}
close () {
this.lineReader.close();
}
async * [Symbol.asyncIterator] () {
try {
while(!this.isClosed) {
yield await this.readLine();
}
} catch (e) {
this.close();
}
}
}
module.exports = LineReader;
测试/ test.js
var LineReader = require("../src/line-reader");
var lineReader = new LineReader(process.stdin);
(async ()=> {
var i = 1;
for await (var line of lineReader) {
console.log(`${i++} ${line}`);
break;
}
console.log(`The line-reader is ${lineReader.isClosed ? "closed" : "open" }.`);
lineReader.close();
})().catch(e=> {
console.error(e)
})
答案 0 :(得分:3)
您可以始终Object.assign
通过被调用的生成函数,并使用return
方法扩展其返回的迭代器。
像这样:
class LineReader {
// ... elided code ...
async * iterate() {
try {
while(!this.isClosed) {
yield await this.readLine();
}
} catch (e) {
this.close();
}
}
[Symbol.asyncIterator] () {
return Object.assign(this.iterate(), {
return: () => {
this.close();
}
});
}
}
或者你也可以选择这样做,但我更喜欢第一种,因为每次调用它都不会创建一个新函数,而第一次看起来好得多。
class LineReader {
// ... elided code ...
[Symbol.asyncIterator] () {
var that = this;
return Object.assign(async function * iterate() {
try {
while(!that.isClosed) {
yield await that.readLine();
}
} catch (e) {
that.close();
}
}(), {
return: () => {
this.close();
}
});
}
}
答案 1 :(得分:1)
只需在finally
块中添加try
即可。 finally
即使函数已经返回也会执行(当有人突然出现for循环时它会返回)。这可以保证您的功能将被清理,您不必修改您的功能。我刚刚发现这一点归功于Jake Archibald的this article。
class LineReader {
// ... elided code ...
async * [Symbol.asyncIterator] () {
try {
while(!this.isClosed) {
yield await this.readLine();
}
} finally {
this.close();
}
}
}