node.js設計模式第二章總結

1.js的回調函數

JS中因爲閉包可以將上下文保存到內存中的特性,使異步中的回調機制在js中使用的更加方便。因此,當operation完成後,callback可以正確執行。異步函數中會使用回調函數,但是使用回調函數的不一定是異步函數。

2.JS的在異步與同步的回調機制

js中的異步函數使用回調機制可能會出現問題。
//異步

const cache = {};
const fs = require("fs");
function instanceReadSyn(filename,callback){
	if(cache[filename]){
		callback(cache[filename]);
	}else{
		fs.readFile(filename,'utf-8',(err,data)=>{
			if(err){
				callback(err);
			}else{
				cache[filename] = data;
				callback(data);
			}
		})
	}
}
function createFileReader(filename){
	const listeners = [];
	instanceReadSyn(filename,(data)=>{
		listeners.foreach((listener)=>{listener(data)});
	})
	return {
		addListener: (listener)=>{listeners.push(listener)}
	}
}
const file1 = createFileReader('lalala.txt');
//第一次打開文件爲異步,所以會異步執行callback,因此callback會在
//file1.addListener執行之後觸發callback回調。
file1.addListener((data)=>{
	console.log("第一次打開");
	//第二次打開文件,因爲cache的存在,因此同步執行callback,但此時
	//file2.addListener沒有執行,所以不會觸發添加的監聽函數。
	const file2 =  createFileReader("alala.txt');
	file2.addListener((data)=>{console.log("第二次打開");})
})
//第一次打開

造成上述問題的原因是因爲,當不存在cache時,異步打開文件從而異步執行callback;當存在cache時,callback同步執行。

因爲異步方法的問題,則改爲同步方法

function instanceReadSyn(filename,callback){
	if(cache[filename]){
		return cache[filename];
	}else{
		cache[filename] = fs.readFileSync(filename,'utf-8');
		return cache[filename]}
}

改進異步方法

function instanceReadSyn(filename,callback){
	if(cache[filename]){
		//就算cache存在也會異步執行callback
		process.nextTick(()=>{
			callback(cache[filename]);
		})
	}else{
		fs.readFile(filename,'utf-8',(err,data)=>{
			if(err){
				callback(err);
			}else{
				cache[filename] = data;
				callback(data);
			}
		})
	}
}
//第一次打開
//第二次打開

SetInmmediate有同樣的作用
Process.nextTick的執行回調是在I/O隊列之前
SetInmmediate的執行回調是在I/O隊列之後
擴展用法有vue源碼中的任務隊列

3.轉換標準

1.callback一般位於輸入參數中的最後一個
2.callback中的error參數一般位於第一個,data數據從第二個參數開始
3.error必須是Error類型的對象
出錯代碼必須得使用try catch,但是可能有時候出現try catch捕獲不到的錯誤
以下代碼當出現JSON.parse(data)中的data不是一個json

function instanceReadSyn(filename,callback){
    if(cache[filename]){
        process.nextTick(()=>{
            callback(cache[filename]);
        })
    }else{
    	//內部的fs.readFile執行成功了,所以try catch沒有捕獲到
        try{
            fs.readFile(filename,'utf-8',(err,data)=>{
                if(err){
                    callback(err);
                }else{
                    cache[filename] = data;
                    callback(null,JSON.parse(data));
                }
            })
        }catch{
            console.log('1');
        }
    }
}

報錯截圖
在這裏插入圖片描述
fs.readFile執行成功了,只是JSON.parse報錯
直接exit輸出到控制檯,這個時候可以使用process.on(‘uncaughtException’,(err)=>{console.log(err);process.exit(1)});推薦出現錯誤直接exit。
改進

try{
    callback(null,JSON.parse(data));
}catch(err){
    console.log(1);
}
//輸出1

4.模塊化

模塊化的作用是

  1. 將所有功能函數與變量私有化,只通過暴露出一個接口供外界進行訪問。
  2. 爲了防止變量污染全局要使用模塊化。

模塊化是是實現過程以require爲例:

const helper = require('aaa.js');

從上述代碼可以看出require的內部實現,先執行aaa.js,然後將需要導出的方法以一個module.export對象的機制返回,module.export對象裏面存放各種方法。

const loadModule = function(filename,module,reqquire){
	const wrapper = `function(filename,module,module.export){
		${fs.readFileSync(filename,'utf-8')}
		}(filename,module,require)`
		eval(wrapper);
	}
	const require = function (filenamet){
	const id = require.resolve(filename);
	const module = {
		id,
		exports: {}
	}
	loadmodule(filename,module,require);
	require.cache[id] = module;
	return module.exports;
}
loadmodule.cache = {};
require.resolve = (filename)=>{
	//返回唯一標識id
}
  • 模塊化導出的方法變量在一個單獨的作用域內部,相同的方法名與變量名可以定義到全局。
  • node.js中的exports僅僅是module.exports的一個副本,通過給exports添加屬性是有用的,但是如果直接改變exports的引用內容將是無效的,因爲沒有改變module.exports的值。
  • 在使用require引用的模塊一般不能引用異步方法,可能會出現錯誤。

require中模塊查找機制

  • 文件模塊: /絕對路徑尋找,./相對路徑尋找

  • 代碼模塊: 如果沒有/或./則直接尋找node.js模塊代碼 包模塊:

  • 如果以上都沒找到,則取尋找node_modele下的模塊

尋找策略

  • ${moduleName}.js
  • ${moduleName}/index.js
  • ${moduleName}/package.json的main屬性中指定的目錄/文件

未完待續

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章