我正在尝试使用带有光纤的光纤:
var Fiber = require('fibers');
var Future = require('fibers/future');
var fs = require('fs');
function sleepForMs(ms) {
var fiber = Fiber.current;
setTimeout(function() {
fiber.run();
}, ms);
Fiber.yield();
}
function catchError(f, onError) {
return function () {
var args = arguments;
var run = function () {
try {
var ret = f.apply(null, args);
}
catch (e) {
onError(e);
}
return ret;
};
if (Fiber.current) {
return run();
}
else {
return Fiber(run).run();
}
}
}
function processFile(callback) {
var count, finished, onData, onException, onIgnoredEntry;
count = 0;
finished = false;
onException = function (error) {
if (finished) {
console.error("Exception thrown after already finished:", error.stack || error);
}
if (finished) {
return;
}
finished = true;
return callback(error);
};
onData = function(data) {
console.log("onData");
if (finished) {
return;
}
console.log("before sleep");
sleepForMs(500);
console.log("after sleep");
throw new Error("test");
};
return fs.createReadStream('test.js').on('data', catchError(onData, onException)).on('end', function() {
console.log("end");
if (finished) {
return;
}
finished = true;
return callback(null, count);
}).on('error', function(error) {
console.log("error", error);
if (finished) {
return;
}
finished = true;
return callback(error);
});
};
Fiber(function () {
console.log("Calling processFile");
Future.wrap(processFile)().wait();
console.log("processFile returned");
}).run();
console.log("back in main");
但它确实不起作用。数据回调在回调内的光纤完成之前完成。所以上面的代码输出:
Calling processFile
back in main
onData
before sleep
end
processFile returned
after sleep
Exception thrown after already finished: Error: test
实际上它应该更像是:
Calling processFile
back in main
onData
before sleep
after sleep
end
processFile returned
Error: test
答案 0 :(得分:0)
这是使用wait.for(Fibers的包装器)https://github.com/luciotato/waitfor
的实现在此实现中,为每个数据块启动光纤,因此并行启动“n”个任务。在所有光纤完成之前,ProcessFile不会“返回”。
这是一个如何使用Fibers& amp; wait.for,但当然你应该在生产中使用它之前将模块级vars和所有函数封装在一个类中。
var wait = require('wait.for');
var fs = require('fs');
var tasksLaunched=0;
var finalCallback;
var callbackDone=false;
var dataArr=[]
function sleepForMs(ms,sleepCallback) {
setTimeout(function() {
return sleepCallback();
}, ms);
}
function resultReady(err,data){
if (err){
callbackDone = true;
return finalCallback(err);
}
dataArr.push(data);
if (dataArr.length>=tasksLaunched && !callbackDone) {
callbackDone = true;
return finalCallback(null,dataArr);
}
}
function processChunk(data,callback) {
var ms=Math.floor(Math.random()*1000);
console.log('waiting',ms);
wait.for(sleepForMs,ms);
console.log(data.length,"chars");
return callback(null,data.length);
}
function processFile(filename,callback) {
var count, onData, onException, onIgnoredEntry;
count = 0;
finalCallback = callback;
onException = function (error) {
if (!callbackDone){
callbackDone = true;
return callback(error);
}
};
onData = function(data) {
console.log("onData");
tasksLaunched++;
wait.launchFiber(processChunk,data,resultReady);
};
fs.createReadStream(filename)
.on('data', onData)
.on('end', function() {
console.log("end");
})
.on('error', function(error) {
console.log("error", error);
if (!callbackDone) {
callbackDone = true;
return callback(error);
}
});
};
function mainFiber() {
console.log("Calling processFile");
var data = wait.for(processFile,'/bin/bash');
console.log(data.length,"results");
console.log("processFile returned");
};
//MAIN
wait.launchFiber(mainFiber);
console.log("back in main");
答案 1 :(得分:0)
减少休眠时间并为其他块设置一些优先级或定时器。 这样在经过一定的时间限制后,可以根据优先级显示块。 这就是你如何以你想要的方式获得输出。
答案 2 :(得分:0)
看起来没有人知道如何做你要问的事。
在这种情况下,您可以以某种传统的异步方式处理流,将结果函数应用于结果。
以下是一些如何操作的例子。
raw-body
一种解决方案是在处理任何流数据之前收集它们。可以使用raw-body
module:
var rawBody = require('raw-body');
function processData(data) {
console.log("before sleep");
sleepForMs(500);
console.log("after sleep");
}
function processFile(callback) {
var stream = fs.createReadStream('fiber.js');
rawBody(stream, function(err, data) {
if (err) return callback(err);
Fiber(processData).run(data); // process your data
callback();
});
}
使用此示例,您将:
Fiber
processData
返回主线程如果需要,您可以添加try ... catch
或任何其他异常处理,以防止processData
破坏您的应用。
但如果您真的想在到达时处理所有数据块,您可以使用一些智能控制流模块。以下是使用queue
feature中的async
module的示例:
function processChunk(data, next) {
return function() {
console.log("before sleep");
sleepForMs(500);
console.log("after sleep");
next();
}
}
function processFile(callback) {
var q = async.queue(function(data, next) {
Fiber(processChunk(data, next)).run();
}, 1);
fs.createReadStream('fiber.js').on('data', function(data) {
q.push(data);
}).on('error', function(err) {
callback(err);
}).on('end', function() {
callback(); // not waiting to queue to drain
})
}
使用此示例,您将:
stream
,push
每个新块到处理队列processData
关闭时从stream
返回主线程,而不是等待处理数据块我知道这不是你所要求的,但我希望它会帮助你。