我有一个带有角度客户端的nodeJS / express / socket.io设置。
从服务器到客户端的消息似乎被阻止,直到长时间运行的进程完成然后一次到达,为什么会这样?
该网站的一个功能是让用户上传xml文件进行处理。文件并非无关紧要,处理大约需要20秒。
我正在使用sax包装器(xml-flow)来解析XML,这会在相关xml标记的末尾引发事件。这些事件调用一个回调,然后调用socket.emit()到客户端来指示进度。
似乎所有内容都可以正常连接,但是进程消息似乎会以某种方式被阻止,直到解析结束,此时它们都会立即到达客户端。使用断点,我已经确定了socket.emit()调用是否定期进行,我不知道任何批处理机制。
如果有帮助,我很乐意发布您认为相关的任何其他代码。
socket.on('analysis:request', function (data) {
// this message arrives immediately
socket.emit('analysis:status', 'Request acknowledged');
// this process takes about 20 seconds, and uses the callback every 2-3 seconds
uploader.processFile(data, function () {
return {
statusUpdate: function (message) {
// these messages arrive all at once at the end of processing
socket.emit('analysis:status', message);
}
}
});
});
function processFile(filename, callback) {
callback().statusUpdate("Unzipping file");
var steps = [];
var zip = new admZip(__dirname + '/' + filename);
var entries = zip.getEntries();
var entry = zip.getEntry(entries[0]);
var bufferStream = new stream.PassThrough;
bufferStream.end(new Buffer(entry.getData()));
callback().statusUpdate("Processing stream");
var xmlStream = flow(bufferStream, { strict: true, preserveMarkup: flow.NEVER, simplifyNodes: false, normalize: false });
xmlStream.on('end', function () {
storeResults(steps, callback);
});
xmlStream.on('error', function (ex) {
console.log('xml-flow error', ex);
});
xmlStream.on('tag:Step', function (element) {
steps.push(element);
if (steps.length % 50 == 0) {
callback().statusUpdate("Caching step " + stepNumber);
}
});
}
更新
嗯,我调查了两个给定的答案,但遗憾的是没有得到满意的结果。
使用process.nextTick
并没有多大帮助,因为长时间运行的过程似乎并没有“放弃嘀嗒”直到它完成
使用sax-async
可以实现我想要的效果,但需要大约三倍的时间。
所以考虑到选择,我在优化解析(预分析,选择性解析等)方面做了很多工作,并设法将其降低到大约12秒,所以可以告诉用户等待而不能表明进展直到完成。
Bounty奖励给了kio,因为它导致了sax-async,它确实起作用,但速度不够快:(
答案 0 :(得分:1)
看起来这个过程是CPU密集型任务,可能它完全阻止了事件循环,直到完成计算。 这是因为node.js应用程序通常在单个线程上运行。
请查看此答案以获取更多详细信息https://stackoverflow.com/a/17957474/4138339
当您执行密集任务时:
我专注于xml-flow模块,但是之前的一些任务也可能是密集型的。我查看了xml-flow源代码,我认为我的解决方案适用于您的特定情况。
当调用此事件'tag:Step'
时,它不会等待您的回调完成。但我们暂停xml-flow,做其他事情并恢复。我没有你的应用程序,因此我无法编写完全正常的工作示例。你必须自己写一下。
对于暂停流使用xmlStream.pause()
,然后调用您的回调,并在一段时间后恢复流xmlStream.resume()
。我认为,为了快速检查,您可以在超时时调用xmlStream.resume(),但对于生产,最好使用process.nextTick
答案 1 :(得分:1)