# 4 – My First Async I\\/O

先搬運題目過來: [learnyounode/problem.zh-tw.md at master · workshopper/learnyounode](https://github.com/workshopper/learnyounode/blob/master/exercises/my_first_async_io/problem.zh-tw.md)

> (題目開始)

## 題目

撰寫一個程式，以 **非同步（ asynchronous ）** 的檔案操作方式讀入一個檔案，並在命令列上顯示該檔案的行數。這個程式的行為類似終端機命令 `cat file | wc -l` 。

程式的第一個命令列參數將是檔案的完整路徑。

## 提示

除了現在您必須以 **Node.js 的** 非同步（asynchronous）方式解決這個習題以外，這個習題的解法 *幾乎* 和前一個習題相同。

您要使用 `fs.readFile()` 取代 `fs.readFileSync()` 方法，相對地，還要用在第二個參數中傳入收集資料的 callback 函式，以取代原本使用回傳值的方法。

請記得， Node.js 的 callback 函式一般會有以下的語法特徵：

```javascript
function callback (err, data) { /* ... */ }
```

所以您就可以藉著檢查第一個參數是否為 True 以確認是不是有錯誤發生。如果沒有錯誤發生，您應該就會可以取得 Buffer 物件作為您的第二個參數。如果使用 `readFileSync()` 方法，您可以在第二參數中改填入「utf8」，然後把 callback 函式放在第三個參數，相對地，您會得到一個 `String` 而非 `Buffer`。

要閱讀 `fs` 模組的文件，可以在瀏覽器中打開這個頁面： {rootdir:/node\_apidoc/fs.html}

> (題目結束)

## 解題思路

可以先參考上一題的答案

```javascript
var fs = require('fs') 
var file = process.argv[2]
var contents = fs.readFileSync(file)

var lines = contents.toString().split('\n').length - 1

console.log(lines)
```

目前想到的是，把 `readFileSync` 替代成 `readFile`，並把 `lines` 和 `console.log(lines)` 包成 callback function。

這是官方解答

```javascript
// 讓 fs 等同 file system
// 取得 [node, node執行位置, filename] 的 filename
var fs = require('fs')
var file = process.argv[2]  

// fs.readFile(filePath, (err, data) )  
fs.readFile(file, function (err, contents) {  
  // fs.readFile(file,'utf8', callback) can also be used  
  if (err) {
    return console.log(err)
  }
  var lines = contents.toString().split('\n').length - 1  
  console.log(lines)  
})
```

雖然好心人部落格有另外一個解法([learnyounode Lesson 4 – My First Async I/O! | Joe Creager](http://joecreager.com/learnyounode-lesson-4-my-first-async-io/))，但我還沒辦法理解，就先用官方的解答結束這回合好了

## 觀念

### readFile

```javascript
fs.readFile('image.png', function (err, buffer) {
  if (err) throw err;
  process(buffer);
});

var text = fs.readFileSync(fileName, 'utf8');

// 将文件按行拆成數組
text.split(/\r?\n/).forEach(function (line) {
  // ...
});
```

* [fs 模塊 -- JavaScript 标準參考教程（alpha）](http://javascript.ruanyifeng.com/nodejs/fs.html)
* [一個 fs.readFileSync 的問題 - CNode 技術社區](https://cnodejs.org/topic/51738afd6d38277306ef98ad)
* [File System | Node.js v7.2.1 Documentation](https://nodejs.org/api/fs.html#fs_fs_readfile_file_options_callback)

### Callback function

* [淺談 javascript 回調函數 - 淺談 JavaScript - 極客學院 Wiki](http://wiki.jikexueyuan.com/project/brief-talk-js/callback-function.html)

### 同步異步

同步就是程式的執行在同一條時間軸上，funciton B() 要等 function A() 執行完後才能執行。一般的程式編寫是如此。

異步就是程式的執行不在同一條時間軸上，function A() 執行時，function B() 也可以執行，不用等 function A()。callback function 就是如此

* [Sync(同步) vs. Async(非同步) | zetafield](https://zetafield.wordpress.com/2015/08/05/sync%E5%90%8C%E6%AD%A5-vs-async%E9%9D%9E%E5%90%8C%E6%AD%A5/)
* [同步與非同步的差異](http://www.victsao.com/blog/81-javascript/319-javascript)
* [JavaScript：徹底理解同步、異步和事件循環 (Event Loop) - 追根溯源 - SegmentFault](https://segmentfault.com/a/1190000004322358)
* [Javascript 異步編程的 4 種方法 - 阮一峰的網絡日志](http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html)
* [Javascript 中非同步執行的一些問題 - iT 邦幫忙:: 一起幫忙解決難題，拯救 IT 人的一天](http://ithelp.ithome.com.tw/articles/10119265)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ayugioh2003.gitbook.io/front2end/shi-zuo/learnyounode/4-my-first-async-io.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
