您現在的位置是:首頁 > 單機遊戲首頁單機遊戲

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

簡介txt’, (err, res1)=>{if(err) console

udietoo怎麼修改地獄火炬

對於用過Nodejs的小夥伴都知道

Nodejs是典型的非同步開發模式, 它最大的優勢也是非同步機制

這種機制帶來巨大的效能優勢的同時, 也帶來了回撥模式引發的回撥地獄問題,從而導致開發者的夢魘

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

作為例子, 先準備3個檔案

先來一個最簡單的回撥樣例:

const fs = require(“fs”);fs。readFile(‘d:/aa。txt’, (err, res1)=>{ if(err) console。error(err); else{ console。log(‘1。。。’, res1。toString()); }});console。log(“2。。。這句是在fs。readFile順序後面的語句。”);

執行結果:

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

結果顯示“2。。。”比“1。。。”先輸出

原因是“1。。。”是在回撥後執行, 比順序執行的“2。。。”慢上半拍

現在提出問題: 要求依次輸出“aa。txt”, “bb。txt”, “cc。txt”的檔案內容, 要怎麼做?

如果按傳統的順序程式設計思路,將會這麼寫:

fs。readFile(‘d:/aa。txt’, (err, res1)=>{ if(err) console。error(err); else{ console。log(‘1。。。’, res1。toString()); }});fs。readFile(‘d:/aa。txt’, (err, res2) => { if (err) console。error(err); else { console。log(‘1。1。。。’, res2。toString()); }});fs。readFile(‘d:/cc。txt’, (err, res3) => { if (err) console。error(err); else { console。log(‘1。2。。。’, res3。toString()); }});console。log(“2。。。這句是在fs。readFile順序後面的語句。”);

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

這是成功了?

哦喲, 居然可以!

其實這是假象! 這個案例中, 3個檔案大小一致, 導致呼叫和回撥時機和時間幾乎相同, 導致看上去好像是“順序執行”成功, 但我們只要把其中一個換成讀取不同大小的檔案, 就能看出區別

比如把bb。txt換成一個稍大一些的HTML檔案, 由於讀取檔案大小不同, 所需的消耗時間也不同, 非同步就表現出不同的結果如下圖

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

很顯然,1。2跑到1。1前面來了

這時候怎麼解決這個問題?

最簡單的思路就是:那就在上一個回撥塊內執行下一個回撥塊:

fs。readFile(‘d:/aa。txt’, (err, res1)=>{ if(err) console。error(err); else{ console。log(‘1。。。’, res1。toString()); fs。readFile(‘d:/aa。html’, (err, res2) => { if (err) console。error(err); else { console。log(‘1。1。。。’, res2。toString()); fs。readFile(‘d:/cc。txt’, (err, res3) => { if (err) console。error(err); else { console。log(‘1。2。。。’, res3。toString()); } }); } }); }});console。log(“2。。。這句是在fs。readFile順序後面的語句。”);

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

這下可以了

應該看出來, 雖然這樣寫能解決問題

但是!

程式碼變得開始難以閱讀

試想一下, 如果這種調用出現10次\10次, 那這程式碼還能讀(維護)嗎? 這就是經典回撥地獄現象

解決辦法也有不少

我們本次先用Q模組來演示怎麼把這種程式碼變得稍微優雅一點

先安裝Q模組

npm install q

然後程式碼改進一下:

const Q = require(“q”);//封裝一下讀檔案的方法function rfile(fn){ let deferred = Q。defer(); fs。readFile(fn, (err, res) => { if (err){ deferred。reject(err); }else { deferred。resolve(res); } }); return deferred。promise;}

讀一個檔案的例子:

let res;rfile(‘d:/aa。txt’)。then((res1) => { res = res1。toString(); console。log(1。1, res);})。then(()=>{ console。log(1。2, res);})console。log(“2。。。這句是在fs。readFile順序後面的語句。”);

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

執行成功

多個檔案按順序怎麼讀呢

let res = [];rfile(‘d:/aa。txt’)。then((res1)=>{ res[0] = res1。toString(); console。log(1。1, res);})。then( rfile(‘d:/bb。txt’)。then((res2) => { res[1] = res2。toString(); console。log(1。2, res); })。then( rfile(‘d:/cc。txt’)。then((res3) => { res[2] = res3。toString(); console。log(1。3, res); })。then(()=>{ console。log(1。4, res); }) ))console。log(“2。。。這句是在fs。readFile順序後面的語句。”);

如何用Q模組的鏈式呼叫來解決nodejs中的回撥地獄問題

與預期結果相符

這種寫法, 與回撥地獄相比,有了很大的改善,多層執行只要同級多個then即可

好像叫瀑布流(序列)的方式?

缺點是要把非同步程式碼封裝在方法裡再呼叫

個人覺得, 這種方法還是不夠徹底

下期用co模組+Promise的方式記錄一篇, 實現真正的順序程式碼方式。

複雜的問題簡單化

每次只關注一個知識點

對技術有興趣的小夥伴可以關注我, 以後會經常分享各種奇奇怪怪又實用的技術知識

Top