Node.js基礎 23456:全域性物件,回撥函式,模組,事件,讀寫檔案(同步,非同步)
全域性物件
全域性變數在所有模組中都可使用。 以下變數雖然看起來像全域性變數,但實際上不是(global裡面沒有以下屬性)。 它們的作用域只在模組內,詳見 文件:
__dirname __filename exports module require()
回撥函式
與js一樣,如:
function callFunction(fun, name) { fun(name); } callFunction(function(name) { console.log(name + ' Bye'); }, 'mtt');
模組
一個大專案一定是分成一個個模組的,一般來說,一個檔案就是一個模組。
模組使用方法:
向外暴露的是一個物件。
我們 require()
的時候,接收的也是一個物件.
所以也可以這樣寫:
app.js
var stuff = require('./count'); console.log(stuff.counter(['ruby', 'nodejs', 'react'])); console.log(stuff.adder(3));//6.14
可以 使用別的模組裡的變數 (閉包)
count.js
var adder = function(a) { return `the sum of the 2 numbers is ${a+pi}`; } var pi = 3.14; module.exports = { counter: function(arr) { return "There are " + arr.length + " elements in the array"; }, adder: adder }
事件
http://nodejs.cn/api/events.html
例如, net.Server
會在每次有新連線時觸發事件, fs.ReadStream
會在開啟檔案時觸發事件, stream
會在資料可讀時觸發事件。
所有能觸發事件的物件都是 EventEmitter
類的例項。 這些物件有一個 eventEmitter.on()
函式,用於將一個或多個函式繫結到命名事件上。 事件的命名通常是駝峰式的字串。
當 EventEmitter
物件觸發一個事件時,所有繫結在該事件上的函式都會被同步地呼叫。
例子,一個簡單的 EventEmitter
例項,綁定了一個監聽器。 eventEmitter.on()
用於註冊監聽器, eventEmitter.emit()
用於觸發事件。
const EventEmitter = require('events'); class MyEmitter extends EventEmitter {} const myEmitter = new MyEmitter(); myEmitter.on('event', () => { console.log('觸發事件'); }); myEmitter.emit('event');
總結理解:
- 觸發器 (Emitter)會觸發 監聽器 (Listener),然後函式會被 同步 呼叫。
- myEmitter.on('event', () => {});用來 繫結 事件與函式(註冊監聽器,
eventEmitter.emit()
用於觸發事件 - 例子:
net.Server
會在每次有新連線時觸發事件,fs.ReadStream
會在開啟檔案時觸發事件,stream
會在資料可讀時觸發事件。
傳引數與 this
到監聽器
http://nodejs.cn/api/events.h...
eventEmitter.emit() 方法可以傳任意數量的引數到監聽器函式。 當監聽器函式被呼叫時,this 關鍵詞會被指向監聽器所繫結的EventEmitter 例項。
const EventEmitter = require('events'); class MyEmitter extends EventEmitter{} const myEmitter1 = new MyEmitter(); myEmitter1.on('exxx',function (a, b) { console.log(a, b, this, this===myEmitter1); }) myEmitter1.emit('exxx','我是a','我是b')
總結:
-
eventEmitter.emit()
從第二個引數開始,會把引數傳到監聽器繫結的那個函式裡面,作為第一個開始. -
this
代表呼叫on
的那個例項
事件只處理一次
當使用 eventEmitter.on()
註冊監聽器時,監聽器會在每次觸發命名事件時被呼叫。
const myEmitter = new MyEmitter(); let m = 0; myEmitter.on('event', () => { console.log(++m); }); myEmitter.emit('event'); // 列印: 1 myEmitter.emit('event'); // 列印: 2
使用 eventEmitter.once()
可以註冊最多可呼叫一次的監聽器。 當事件被觸發時,監聽器會被登出,然後再呼叫。
const myEmitter = new MyEmitter(); let m = 0; myEmitter.once('event', () => { console.log(++m); }); myEmitter.emit('event'); // 列印: 1 myEmitter.emit('event'); // 不觸發
require('events')
手動用程式碼觸發事件。
util(實用工具)(nodejs核心工具庫)
http://nodejs.cn/api/util.htm...var events = require('events'); var util = require('util');//nodejs工具庫 var Person = function(name) { this.name = name } util.inherits(Person, events.EventEmitter); //讓Person繼承events.EventEmitter(也可以用ES6寫法的extends關鍵字),讓他擁有可以繫結事件,觸發事件的功能。 var xiaoming = new Person('xiaoming'); var lili = new Person('lili'); var lucy = new Person('lucy'); //新生成三個物件 var person = [xiaoming, lili, lucy]; person.forEach(function(person) { person.on('speak', function(message) { console.log(person.name + " said: " + message);//給每一個新物件繫結事件 }) }) xiaoming.emit('speak', 'hi');//每一個新物件都可以觸發事件 lucy.emit('speak', 'I want a curry');
讀寫檔案(同步,非同步)
檔案系統: http://nodejs.cn/api/fs.html
fs 模組用於以一種類似標準 POSIX 函式的方式與檔案系統進行互動。
使用方法如下:
const fs = require('fs');
所有的檔案系統操作都有 同步 和 非同步 兩種形式。
非同步
非同步形式的最後一個引數是完成時的回撥函式。 傳給回撥函式的引數取決於具體方法,但 第一個引數 會保留給 異常 。 如果操作成功完成,則第一個引數(異常)會是 null
或 undefined
。
const fs = require('fs'); fs.unlink('/tmp/hello', (err) => { if (err) throw err; console.log('成功刪除 /tmp/hello'); });
同步
當使用同步操作時,任何異常都會立即丟擲,可以使用 try/catch
處理異常。
const fs = require('fs'); try { fs.unlinkSync('/tmp/hello'); console.log('成功刪除 /tmp/hello'); } catch (err) { // 處理異常。 }
同步非同步注意
非同步的方法不能保證執行順序。 所以下面的例子可能會出錯,因為 fs.stat()
可能在 fs.rename()
之前完成:
fs.rename('/tmp/hello', '/tmp/world', (err) => { if (err) throw err; console.log('重新命名完成'); }); fs.stat('/tmp/world', (err, stats) => { if (err) throw err; console.log(`檔案屬性: ${JSON.stringify(stats)}`); }); 要想按順序執行操作,需要把 fs.stat() 放到 fs.rename() 的回撥函式中: fs.rename('/tmp/hello', '/tmp/world', (err) => { if (err) throw err; fs.stat('/tmp/world', (err, stats) => { if (err) throw err; console.log(`檔案屬性: ${JSON.stringify(stats)}`); }); });