2015-12-01 85 views
1

我想了解nodejs異步行爲。考慮瞭解`nodejs`異步文件讀取

### text file: a.txt ### 
1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
{{b.txt}} 
3. Donec et mollis dolor. 
{{c.txt}} 
######################## 

### text file: b.txt ### 
2. Donec a diam lectus. Sed sit amet ipsum mauris. 
######################## 


### text file: c.txt ### 
4. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. 
######################## 

var readFile = function(file) { 
    fs.readFile(file, "utf8", function (err, file_content) { 
     if (err) console.log("error: " + err); 

     file_content.split(/\n/) 
      .forEach(function(line) { 
       var found = line.match(/\{\{(.*?)\}\}/); 
       found ? readFile(found[1]) : console.log(line); 
      }); 
    }); 
}; 

我想輸出是

1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
2. Donec a diam lectus. Sed sit amet ipsum mauris. 
3. Donec et mollis dolor. 
4. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. 

我得到的輸出是

1. Lorem ipsum dolor sit amet, consectetur adipiscing elit. 
3. Donec et mollis dolor. 
2. Donec a diam lectus. Sed sit amet ipsum mauris. 
4. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. 

我該如何解決這個問題?完成這樣一個任務的最習慣的方式是什麼?

更新:我想在這裏指出,我想用readFileSyncasync(目前,至少)。現在,我想了解用普通JS實現這一點的正確方法,並在此過程中更好地理解異步編程。

+0

您可以利用readFileSync,或者你使用異步庫實現這一目標。 –

+0

感謝您的評論,但我*不想*使用'readFileSync'或'async'(至少現在)。目前,我想了解用普通JS做這件事的正確方法。 – punkish

回答

2

你實質上要求做的是在繼續下一行之前,讓逐行迭代等待異步操作readFile(found[1])完成。由於這是一個異步操作,它不會暫停您的Javascript執行。由於它不會暫停執行,因此.forEach()的其餘部分會繼續運行,並且readFile(found[1])的結果會與正在發生的其他任何事情交織在一起。

這樣的問題的唯一解決方案是對迭代進行更多的控制,以便下一次迭代的行不會繼續,直到處理完當前的迭代爲止。您將不得不停止使用.forEach()並進行手動迭代。

下面是關於如何使具有手動迭代的功能工作總體思路:

var readFile = function(file, done) { 
    fs.readFile(file, "utf8", function (err, file_content) { 
     if (err) { 
      console.log("error: ", err); 
      done(err); 
      return; 
     } 

     var lines = file_content.split(/\n/); 
     var cntr = 0; 

     function nextLine() { 
      var found, line, more = false; 
      while (cntr < lines.length) { 
       line = lines[cntr++]; 
       found = line.match(/\{\{(.*?)\}\}/); 
       if (found) { 
        readFile(found[1], function(err) { 
         if (err) { 
          return done(err); 
         } 
         nextLine(); 
        }); 
        more = true; 
        // break out of the while loop and let this function finish 
        // it will get called again when the async operation completes 
        break; 
       } else { 
        console.log(line); 
       } 
      } 
      // if we're all done, then call the callback to 
      // to tell the caller we're done with all async stuff 
      if (!more) { 
       done(null); 
      } 
     } 
     // start the first iteration 
     nextLine(); 
    }); 
}; 

// call it initially like this 
readFile("somefile.text", function(err) { 
    if (err) console.log(err); 
}); 
+0

你的評論是有道理的。您能否給我舉一個例子,說明我如何進行手動迭代*? – punkish

+0

@punkish - 我添加了一個手動迭代的例子。 – jfriend00

+0

謝謝@ jfriend00的代碼。這有很大幫助。我會做的唯一編輯是添加''var done = function(err){if(err)console.log(err);返回; };代碼。 – punkish