異步發(fā)展歷程,js走過的那十年

js中異步的發(fā)展跌跌撞撞走了十年菩暗,從開始的回調惡魔發(fā)展到現(xiàn)在的仿佛同步的寫法揪胃。再次回顧署海,特此總結。

先簡述一下我們遇到的問題:
當我們訪問一個頁面的時候肄方,我們可能需要讀取兩個文件冰垄,一個是模板文件,一個是這個頁面的數(shù)據(jù)文件权她。引為讀取文件都比較耗時虹茶,我們通過異步來處理。

let fs = require('fs');
fs.readFile('./template.txt', 'utf8', function (err, template) {
    fs.readFile('./data.txt', 'utf8', function (err, data) {
        console.log(template + ' ' + data);
    })
})

看上去好像沒有什么問題隅要,兩層的嵌套好像還能接受蝴罪,但是如果請求data.txt后有需要其他文件的數(shù)據(jù),這樣層層嵌套下去會出現(xiàn)什么現(xiàn)象呢步清?

fs.readFile('./template.txt', 'utf8', function (err, template) {
    fs.readFile('./data.txt', 'utf8', function (err, data) {
        fs.readFile('./data2.txt', 'utf8', function (err, data1) {
            fs.readFile('./data3.txt', 'utf8', function (err, data2) {
                fs.readFile('./data4.txt', 'utf8', function (err, data3) {
                    console.log(template + ' ' + data + ' ' + data1 + ' ' + data2 + ' ' + data3);
                })
            })
        })
    })
})

如果這是被人的代碼要门,你要改其中的一部分虏肾。什么感受?
這就是傳說中的回調金字塔欢搜,又叫回調地獄封豪。它使js代碼變的非常難看和難以維護并且效率低下。
如何解決這個問題炒瘟?

事件發(fā)布訂閱

我們可以通過node核心模塊中的 EventEmitter 類來實現(xiàn)吹埠,通過它可以創(chuàng)建事件發(fā)射器的實例,里面有兩個核心方法疮装,一個叫on缘琅,一個叫emit。on表示注冊監(jiān)聽事件廓推,emit表示發(fā)射事件胯杭。

let fs = require('fs');
let EventEmitter = require('events');
let eve = new EventEmitter();
let html = {};//存放最終數(shù)據(jù)

//監(jiān)聽數(shù)據(jù)獲取成功事件,當事件發(fā)生之后調用回調函數(shù)
eve.on('ready', function (key, value) {
    html[key] = value;
    if (Object.keys(html).length == 2) {
     console.log(html);//在此能夠獲取到兩個文件的數(shù)據(jù)受啥。
     }
});
fs.readFile('./template.txt', 'utf8', function (err, template) {
    //‘ready’為事件名 做个,往后是傳遞給回調函數(shù)的參數(shù)
    eve.emit('ready', 'template', template);
})
fs.readFile('./data.txt', 'utf8', function (err, data) {
    eve.emit('ready', 'data', data);
});

請求template.txt和data.txt文件數(shù)據(jù),當成功后發(fā)布ready事件滚局。on處訂閱了ready事件居暖,當他觸發(fā)的時候,on方法執(zhí)行藤肢。
有點兒類似我們的綁定事件比如:onClick太闺,給一個元素綁定onClick事件,當頁面觸發(fā)的時候再執(zhí)行嘁圈。

哨兵變量

let fs = require('fs');
function render(length, cb) {
    let html = {};
    return function (key, value) {
        html[key] = value;
        if (Object.keys(html).length == length) {
            cb(html);
        }
    }
}
//2是一個哨兵變量省骂,將讀取文件數(shù)據(jù)成功后執(zhí)行的方法作為回調函數(shù)傳給render方法。
let done = render(2, function (html) {
    console.log(html);
});
fs.readFile('./template.txt', 'utf8', function (err, template) {
    done('template', template);
})
fs.readFile('./data.txt', 'utf8', function (err, data) {
    done('data', data);
})

不使用回調嵌套遇到的問題是:不知道讀取文件的函數(shù)什么時候執(zhí)行完最住。因為只有全部執(zhí)行完后才能執(zhí)行需要文件數(shù)據(jù)的方法钞澳。
上面代碼render方法執(zhí)行時傳入的2相當于一個哨兵變量,可以是2涨缚,可以是3轧粟,取決于后面需要讀取幾個文件的數(shù)據(jù)。將需要讀取的文件數(shù)量脓魏,和讀取全部文件成功后的方法作為回調函數(shù)傳入render兰吟。done為render執(zhí)行后返回的函數(shù)。
每次獲取文件成功后執(zhí)行done方法即可茂翔。
通過這種方法也可以獲取到最終全部文件的數(shù)據(jù)混蔼。

Promise/Deferred模式

let fs = require('fs');
function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, function (err, data) {
      if (err)
        reject(err);
      else
        resolve(data);
    })
  })
}
function *read() {
  let template = yield readFile('./template.txt');
  let data = yield readFile('./data.txt');
  return template + '+' + data;
}
co(read).then(function (data) {
  console.log(data);
}, function (err) {
  console.log(err);
});

Async/ await

let fs = require('fs');
function readFile(filename) {
  return new Promise(function (resolve, reject) {
    fs.readFile(filename, 'utf8', function (err, data) {
      if (err)
        reject(err);
      else
        resolve(data);
    })
  })
}

async function read() {
  let template = await readFile('./template.txt');
  let data = await readFile('./data.txt');
  return template + '+' + data;
}
let result = read();
result.then(data=>console.log(data));
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市珊燎,隨后出現(xiàn)的幾起案子惭嚣,更是在濱河造成了極大的恐慌遵湖,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件料按,死亡現(xiàn)場離奇詭異,居然都是意外死亡卓箫,警方通過查閱死者的電腦和手機载矿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來烹卒,“玉大人闷盔,你說我怎么就攤上這事÷眉保” “怎么了逢勾?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長藐吮。 經(jīng)常有香客問我溺拱,道長,這世上最難降的妖魔是什么谣辞? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任迫摔,我火速辦了婚禮,結果婚禮上泥从,老公的妹妹穿的比我還像新娘句占。我一直安慰自己,他們只是感情好躯嫉,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布纱烘。 她就那樣靜靜地躺著,像睡著了一般祈餐。 火紅的嫁衣襯著肌膚如雪擂啥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天帆阳,我揣著相機與錄音啤它,去河邊找鬼。 笑死舱痘,一個胖子當著我的面吹牛变骡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芭逝,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼塌碌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了旬盯?” 一聲冷哼從身側響起台妆,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤翎猛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后接剩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體切厘,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年懊缺,在試婚紗的時候發(fā)現(xiàn)自己被綠了疫稿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡鹃两,死狀恐怖遗座,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情俊扳,我是刑警寧澤途蒋,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站馋记,受9級特大地震影響号坡,放射性物質發(fā)生泄漏。R本人自食惡果不足惜梯醒,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一筋帖、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冤馏,春花似錦日麸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至涕刚,卻和暖如春嗡综,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背杜漠。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工极景, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驾茴。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓盼樟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锈至。 傳聞我的和親對象是個殘疾皇子晨缴,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法峡捡,內(nèi)部類的語法击碗,繼承相關的語法筑悴,異常的語法,線程的語...
    子非魚_t_閱讀 31,622評論 18 399
  • 國家電網(wǎng)公司企業(yè)標準(Q/GDW)- 面向對象的用電信息數(shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,957評論 6 13
  • 古單朱氏: 泛指主要居住在魯稍途、蘇阁吝、豫、皖等省15個縣械拍、市周邊600多個村莊以及因各種因素遷往另外省市突勇、縣的...
    古單朱氏閱讀 1,900評論 0 1
  • 鯨魚閱讀超好看的黑色幽默生活小說《對岸》,第33章發(fā)布殊者,看看作為受害者的周大春与境,是如何在絕境中求生的吧验夯,我們身邊這...
    山和仙閱讀 227評論 0 1