nodejs異步編程的體現(xiàn)就是回調(diào)
異步編程依托于回調(diào)來實現(xiàn),但不能說使用了回調(diào)后程序就異步化了。
回調(diào)函數(shù)在完成任務(wù)后就會被調(diào)用,Node使用了大量的回調(diào)函數(shù),Node所有的API都支持回調(diào)函數(shù)。
例如,我們可以一邊讀取文件,一邊執(zhí)行其他命令,在文件讀取完后,我們將文件內(nèi)容作為回調(diào)函數(shù)的參數(shù)返回。
fs是文件系統(tǒng)模塊,同時提供了異步和同步的方法
阻塞代碼
創(chuàng)建一個文件 input.txt,內(nèi)容如下:
hello
創(chuàng)建main.js文件,代碼如下
var fs = require('fs');
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("程序執(zhí)行結(jié)束!");
以上代碼執(zhí)行結(jié)果如下:
$ node main.js
hello
程序執(zhí)行結(jié)束!
同步操作的好處是代碼簡單,缺點是程序?qū)⒌却齀O操作,在等待時間內(nèi),無法響應(yīng)其他任何事件。而異步讀取不需要等待IO操作,但代碼比較麻煩。
非阻塞代碼
創(chuàng)建一個文件 input.txt,內(nèi)容如下:
hello
創(chuàng)建main.js文件,代碼如下
var fs = require('fs');
fs.readFile('input.txt', 'utf-8', function (err, data) {
if(err) {
console.log(err);
}else {
console.log(data);
}
});
console.log("程序執(zhí)行結(jié)束!");
以上代碼執(zhí)行結(jié)果如下:
$ node main.js
程序執(zhí)行結(jié)束!
hello
注意:input.txt文件必須在當(dāng)前目錄下,且文件編碼為utf-8.
異步讀取時,傳入的回調(diào)函數(shù)接受兩個參數(shù),當(dāng)正常讀取時,err參數(shù)為null,data參數(shù)為讀取到的string。當(dāng)讀取發(fā)生錯誤時,err參數(shù)代表一個錯誤對象,data為undefined。這也是Nodejs標準的回調(diào)函數(shù):第一個參數(shù)代表錯誤信息,第二個參數(shù)代表結(jié)果。
如果讀取的文件不是文本文件,而是二進制呢?
下面是讀取一個圖片的代碼
var fs = require('fs');
fs.readFile('sample.png', function(err, data) {
if(err) {
console.log(err);
}else {
console.log(data);
console.log(data.length + 'bytes');
}
});
當(dāng)讀取二進制文件時,不傳入文件編碼時,回調(diào)函數(shù)的data參數(shù)將返回一個Buffer對象。在Node.js中,Buffer對象就是一個包含零個或任意個字節(jié)的數(shù)組(和Array不同)。
Buffer對象可以和String相互轉(zhuǎn)換,例如把一個Buffer對象轉(zhuǎn)換成String:
// Buffer -> String
var text = data.toString('utf-8');
或者把一個String轉(zhuǎn)換成Buffer
// String -> Buffer
var buf = Buffer.from(text, 'utf-8');