我意识到节点是非阻塞的,但是,我也意识到因为节点只有一个线程,所以在事件循环的中间放置一个三秒的while
循环会导致阻塞。 即:
var start = new Date();
console.log('Test 1');
function sleep(time, words) {
while(new Date().getTime() < start.getTime() + time);
console.log(words);
}
sleep(3000, 'Test 2'); //This will block
console.log('Test 3') //Logs Test 1, Test 2, Test 3
我看到的许多处理新"Streams2"接口的示例看起来都会导致同样的阻塞。例如这个,从这里借来的:
var crypto = require('crypto');
var fs = require('fs');
var readStream = fs.createReadStream('myfile.txt');
var hash = crypto.createHash('sha1');
readStream
.on('readable', function () {
var chunk;
while (null !== (chunk = readStream.read())) {
hash.update(chunk); //DOESN'T This Cause Blocking?
}
})
.on('end', function () {
console.log(hash.digest('hex'));
});
如果我遵循正确的内容,当缓冲区中有数据时,readStream
将发出 readable
事件。 因此,似乎一旦发出readable
事件,整个事件循环就会停止,直到readStream.read()
发出 null。 这似乎不如旧方法可取(因为它不会阻塞)。有人可以告诉我为什么我错了。 谢谢。
内部流缓冲区为空之前,您不必读取。如果你愿意,你可以只读一次,然后在一段时间后再读另一个块。
readStream.read()
本身不是阻塞,但hash.update(chunk)
(在短时间内)是因为哈希是在主线程上完成的(关于添加将在线程池中执行加密函数的异步接口存在 github 问题)。
此外,您可以简化使用加密流接口的代码:
var crypto = require('crypto'),
fs = require('fs');
var readStream = fs.createReadStream('myfile.txt'),
hasher = crypto.createHash('sha1');
readStream.pipe(hasher).on('readable', function() {
// the hash stream automatically pushes the digest
// to the readable side once the writable side is ended
console.log(this.read());
}).setEncoding('hex');
所有 JS 代码都是单线程的,因此循环会阻塞,但您误解了该循环将运行多长时间。调用 .read()
从流中获取可读项,就像与该项一起调用"数据"处理程序一样。一旦没有项目,它将停止执行并取消阻止。每当有数据时都会触发"可读",然后清空缓冲区并等待另一个"可读"。因此,您的第一个while
循环依赖于要更新的时间,这可能是一些无限的时间量,另一个循环基本上是在执行:
while (items.length > 0) items.pop()
这几乎是处理流中的项目所需的最少工作量。