介面卡模式:非同步轉化為同步。
日常開發中會經常不知不覺的使用到各種設計模式,這裡以nodejs中非同步呼叫轉化為同步呼叫為例,一起探索下介面卡模式。(本文的旨在為把複雜的東西簡單化,理清思路換位思考,相信看完本文你應該會掌握處理複雜問題的思路)
如果熟悉nodejs的同學應該會對node各種非同步程式設計庫有所涉獵。這裡我不講那些庫,只是講解一個簡單的函式實現,以此來切入介面卡模式。
此時,我想把nodejs的非同步函式,改為promise的方式呼叫,即aa('xx').then().then();這樣。此時就需要一個介面卡,來轉化下我們的非同步函式,如果你的抽象思維比較好,腦子裡有一整套模型,那輕易就能寫出一個轉化函式。但是,很多時候我們沒有那麼高的抽象能力,怎麼辦呢?從結果入手。下面是一個例項:
改造前fs.readFile('xxx', function(data){});
期望改造後的結果是aaa('xxx).then(function(data) {});
aaa怎麼來的呢?就是透過介面卡模式生成的函式:var aaa = cb2Promise(fs.readFile);
從結果入手,那就容易了。首先要建立一個cb2Promise函式,然後他需要一個函式作為引數,返回一個可以呼叫函式,次函式呼叫的返回的結果是promise物件。 一步一步來:
function cb2Promise(func) {
return function () {
return new Promise(function(resolve, reject){});
}
}
大體的構架已經出來了。現在就是完善內容。
第二步,我們傳入了一個函式,這個函式就是我們實際呼叫的東西:
function cb2Promise(func) {
return function () {
return new Promise(function(resolve, reject){
func();
});
}
}
現在問題來了func需要兩個引數,第一個是url第二個是回撥。但是,現在引數從哪裡來呢?從結果來 aaa('xxx).then(function(data) {}); 這裡我們不是傳入了一個'xxx'了麼。這個怎麼獲取呢?此時有兩種方式,第一種最簡單的,直接以形參的方式傳入:
function cb2Promise(func) {
return function (path) {//path從呼叫時傳入
return new Promise(function(resolve, reject){
func(path, function(err, data) {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
}
這樣是不是很簡單的解決了問題。第二種方式是採用arguments來獲取,這種方式對擴充套件性比較友好,(你如你想fs.open('xxx', 'w+', function() {}))這個難道還得再寫一個函式麼,這不科學。所以用arguments來獲取引數擴充套件性更好。具體怎麼做呢?這時,我們想到了call和applay函式,而arguments為類陣列物件,很明顯此時我們用arguments函式:
function cb2Promise(func) {
return function () {//path從呼叫時傳入
var args = arguments;
return new Promise(function(resolve, reject){
func.apply(args , function(err, data) {//有問題
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
}
額,是不是感覺那裡不對了?是的 func.apply(args , function(err, data) {})此時引數有兩個,我們實際需要的只是一個陣列。所以,我們想著把回撥函式放到args中去。此時應該這樣做:
function cb2Promise(func) {
return function () {
var arg = arguments ? [].slice.apply(arguments) : [];
return new Promise(function (resolve, reject) {
arg.push(function(err, data) {
if (err){
reject(err);
} else {
resolve(data);
}
})
func.apply(this, arg);
})
}
}
是不是很簡單,然後我們再稍微加一點錯誤處理,讓程式更健壯穩定:
function cb2Promise(func) {
if (typeof func !== 'function') throw new Error('第一個引數必須為函式');
return function () {
var arg = arguments ? [].slice.apply(arguments) : [];
return new Promise(function (resolve, reject) {
arg.push(function(err, data) {
if (err){
reject(err);
} else {
resolve(data);
}
})
func.apply(this, arg);
})
}
}
這樣一個簡單的介面卡就完成時,一步步下來是不是很簡單。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3137/viewspace-2798850/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- [轉]阻塞/非阻塞與同步/非同步非同步
- 同步非同步,阻塞非阻塞非同步
- 非同步、同步、阻塞、非阻塞非同步
- 同步、非同步、阻塞、非阻塞非同步
- 同步非同步 與 阻塞非阻塞非同步
- 理解阻塞、非阻塞、同步、非同步非同步
- 同步、非同步,阻塞、非阻塞理解非同步
- 同步、非同步、阻塞與非阻塞非同步
- 同步、非同步、阻塞和非阻塞非同步
- oracle rac CTSS時鐘同步模式轉換為NTP同步模式的實施記錄(4)Oracle模式
- oracle rac CTSS時鐘同步模式轉換為NTP同步模式的實施記錄(3)Oracle模式
- oracle rac CTSS時鐘同步模式轉換為NTP同步模式的實施記錄(2)Oracle模式
- oracle rac CTSS時鐘同步模式轉換為NTP同步模式的實施記錄(1)Oracle模式
- 同步與非同步 阻塞與非阻塞非同步
- Socket程式設計中的同步、非同步、阻塞和非阻塞(轉)程式設計非同步
- 同步、非同步、阻塞、非阻塞的區別非同步
- 乾坤大挪移,如何將同步阻塞(sync)三方庫包轉換為非同步非阻塞(async)模式?Python3.10實現。非同步模式Python
- 徹底搞懂同步非同步與阻塞非阻塞非同步
- IO - 同步 非同步 阻塞 非阻塞的區別非同步
- 同步、非同步、阻塞、非阻塞的簡單理解非同步
- 同步與非同步、阻塞與非阻塞的理解非同步
- java同步非阻塞IOJava
- 非同步和非阻塞非同步
- 同步模式(Synchronous)模式
- IO模式和IO多路複用(阻塞IO、非阻塞IO、同步IO、非同步IO等概念)模式非同步
- 同步阻塞、同步非阻塞、多路複用的介紹
- 非同步程式碼模式轉換(node)非同步模式
- 【設計模式】非同步阻塞、非同步回撥模式設計模式非同步
- nodejs非同步轉同步NodeJS非同步
- 大白話搞懂什麼是同步/非同步/阻塞/非阻塞非同步
- socket阻塞與非阻塞,同步與非同步、I/O模型非同步模型
- 網路IO之阻塞、非阻塞、同步、非同步總結非同步
- IO通訊模型(二)同步非阻塞模式NIO(NonBlocking IO)模型模式BloC
- 譯/非同步程式碼模式轉換(node)非同步模式
- 非同步模式(Asynchronous)非同步模式
- 怎樣理解阻塞非阻塞與同步非同步的區別?非同步
- 一篇文章讀懂阻塞,非阻塞,同步,非同步非同步
- ♻️同步和非同步;並行和併發;阻塞和非阻塞非同步並行