js非同步遞迴方式
阿新 • • 發佈:2021-01-31
技術標籤:node.jsjavascript
js非同步遞迴方式
寫下自己的思考是個好習慣,可以總結自己的學習和智慧,鞏固知識,也可以讓自己不犯同樣錯誤。希望自己可以堅持下來。
問題
遞迴就是自己呼叫自己,然後通過呼叫自己得到的結果來計算當前結果
斐波那契數列的遞迴計算方式就是一種典型的例子
function feb (n) {
if (n == 1 || n == 2) return 1
return feb(n - 2) + feb(n - 1)
}
這裡有一個重要的地方在於:要得到呼叫自己的結果
那麼自己是一個非同步函式,就會出現得不到自己的結果這種情況
因為非同步函式會在同步程式碼執行完之後執行
也就是說,遞迴不起來了
解決方法
js 提供了 Promise
類,可以解決這個問題
假設我們要通過 fs.readdir()
這個非同步方法來遞迴讀取某個路徑下的所有檔名
我們可以先通過 Promise
把 fs.readdir()
這個非同步方法封裝起來
new Promise((resolve, reject) => {
fs.readdir(path, 'utf-8', function (err, data) {
if (err) reject(err);
else resolve(data)
})
})
這樣一來,我們就可以通過 async
和 await
由於遞迴時我們會多次呼叫 fs.readdir()
函式,每次的訪問的路徑都是不一樣的,所以我們需要一個Promise工廠
function asyncReadDir (path) {
return new Promise((resolve, reject) => {
fs.readdir(path, 'utf-8', function (err, data) {
if (err) reject(err);
else resolve(data)
})
})
}
這樣一來我們就可以通過這個工廠函式,輕鬆的得到一個封裝後的 fs.readdir()
有了這個工廠函式和 async
和 await
,我們可以簡單實現一個遞迴操作實現需求
async function dfsFileNames (path) {
const data = await asyncReadDir(path)
const res = []
for (const fileName of data) {
res.push(fileName)
if (!fileName.includes('.')) {
res.push(await dfsFileNames(`${path}/${fileName}`))
}
}
return res
}
注意,async
函式 返回的結果是一個 Promise
,想要獲取結果可以通過 .then()
或者 async
+ await
完整程式碼
const fs = require('fs');
function asyncReadDir (path) {
return new Promise((resolve, reject) => {
fs.readdir(path, 'utf-8', function (err, data) {
if (err) reject(err);
else resolve(data)
})
})
}
async function dfsFileNames (path) {
const data = await asyncReadDir(path)
const res = []
for (const fileName of data) {
res.push(fileName)
if (!fileName.includes('.')) {
res.push(await dfsFileNames(`${path}/${fileName}`))
}
}
return res
}
const fetchFileNames = dfsFileNames('./')
fetchFileNames.then(res => {
console.log(res);
})