我读过这篇文章,我有一个特别的疑问,如果有人向我澄清。
http://debuggable.com/posts/understanding-node-js:4bd98440-45e4-4a9a-8ef7-0f7ecbdd56cb
var fs = require('fs')
, sys = require('sys');
fs.readFile('treasure-chamber-report.txt', function(report) {
sys.puts("oh, look at all my money: "+report);
});
fs.writeFile('letter-to-princess.txt', '...', function() {
sys.puts("can't wait to hear back from her!");
});您的代码为节点提供读取和写入文件的两个任务,然后进入休眠状态。一旦节点完成了任务,它的回调就会被触发。但同时只能有一个回调射击。在该回调完成之前,所有其他回调都必须排队等待。除此之外,还不能保证回调的启动顺序。
“那么我就不用担心代码同时访问相同的数据结构了吗?”!这就是JavaScripts单线程/事件循环设计的全部美!
发布于 2012-11-13 17:14:23
1)如果您运行的是单线程,则不必担心多线程应用程序所带来的问题。这包括两个不同的线程,试图同时使用同一个对象。例如,假设一个线程试图从哈希读取数据,而另一个线程从相同的哈希中删除数据。键/值对看起来可能在一行代码中存在,但由于到下一行时线程化,数据可能不再存在。类似地,您不必处理避免这些问题所涉及的所有额外代码和头痛。
2)见#1,与其说这是一个问题,不如说是一个权衡。现在很多计算机都有多个处理器/核,所以一个程序一次使用多个线程是有益的。当您期望线程被阻塞时,它也很有用。例如,在另一种多线程语言中,通常会读取文件的内容,并在不添加回调的情况下输出它们。但是,这意味着在文件读取操作完成之前,线程在那里什么都不做(阻止)。多线程编程也很难正确执行。
( 3)你不会不服从命令的。如果您希望确保正确的顺序,则等待执行第二个调用,直到第一个调用返回。例如:
fs.readFile('treasure-chamber-report.txt', function(report) {
sys.puts("oh, look at all my money: "+report);
fs.writeFile('letter-to-princess.txt', '...', function() {
sys.puts("can't wait to hear back from her!");
});
});请注意,这有时会让您进入通常被称为“回调地狱”的状态。
编辑:处理您的评论:
1)尽管您正在“等待”NodeJS文件的读取,但在NodeJS中,这是一种非阻塞操作。这意味着即使在读取文件之前,方法调用(readFile)也会立即返回。这是因为它将数据IO请求传递给底层操作系统,而底层操作系统拥有自己的线程来处理此类请求。当操作系统完成读(或写)时,它会通知原始进程它已经准备好了数据。当操作系统执行此工作时,NodeJS可以让它的一个线程在等待时继续执行其他工作。这就是为什么需要回调的原因--当您最终获得数据时,您需要一种告诉NodeJS下一步该做什么的方法。
2)从本质上讲,回调地狱没有什么不好之处,只是它很难读懂。人们可能会想象,如果您要做的工作包括几个不同的异步进程(比如读取和写入磁盘),那么您可能会得到如下所示的内容:
var doSomething function(){
fs.readFile('step1.txt', function(result){
// do something with the result
fs.writeFile('step2.txt', function(){
// okay, step2 is ready, so process that
fs.readFile('step2.txt', function(result){
fs.writeFile('step3.txt', function(){
//etc, etc
});
});
});
});
}你可以看到嵌套很快就会变得很深,而且很难读懂。如果您搜索"JavaScript回调地狱“,这里和其他地方都会讨论这个问题。一种将事情扁平化的方法是避免内联/匿名函数,并使用命名函数将其扁平化,这样您的回调就不会嵌套在编辑器中那么深的位置(尽管从词汇的角度来看嵌套仍然在进行)。
https://stackoverflow.com/questions/13365213
复制相似问题