2017-10-20 74 views
0

我正在使用ramdadata.task編寫一個小型實用程序,它可以從目錄中讀取圖像文件並輸出它們的大小。我得到它的工作就像這樣:如何用Ramda.js重構這個組合函數?

const getImagePath = assetsPath => item => `${assetsPath}${item}` 

function readImages(path) { 
    return new Task(function(reject, resolve) { 
    fs.readdir(path, (err, images) => { 
     if (err) reject(err) 
     else resolve(images) 
    }) 
    }) 
} 

const withPath = path => task => { 
    return task.map(function(images) { 
    return images.map(getImagePath(path)) 
    }) 
} 

function getSize(task) { 
    return task.map(function(images) { 
    return images.map(sizeOf) 
    }) 
} 

const getImageSize = dirPath => compose(getSize, withPath(dirPath), readImages) 

的問題是與withPath功能,增加了正確的圖像的圖像的路徑文件名,但迫使我的API中的目錄名通過兩次:一次讀取文件和第二閱讀路徑的時間。這意味着我必須調用getImageSize功能,像這樣:

const portfolioPath = `${__dirname}/assets/` 

getImageSize(portfolioPath)(portfolioPath).fork(
    function(error) { 
    throw error 
    }, 
    function(data) { 
    console.log(data) 
    } 
) 

有什麼辦法打發dirname作爲參數只有一次?我希望API像這樣的工作:

getImageSize(portfolioPath).fork(
    function(error) { 
    throw error 
    }, 
    function(data) { 
    console.log(data) 
    } 
) 
+1

我在我的手機現在這麼不能真正的測試,但你可能檢查['chain'](http://ramdajs.com/docs/#chain)如何處理函數:'chain(f,g)(x)=> f(g(x),x)'。 –

+0

嘿@ScottSauyet - 希望得到你的關注。我解決了這個問題,但我仍然想了解在這種情況下我將如何使用鏈。拉姆達中的「鏈」不僅僅是「平面圖」嗎? 這將如何適用? –

+1

我在想你可能可以將'withPath'切換到'task => path => ...',然後用'chain(withPath,readImages)'編寫'getSize'。至於「鏈」如何在函數上工作,斯科特·克里斯托弗提供了一個[優秀的答案](https://stackoverflow.com/a/45787799/1243641)。 –

回答

1

你不應該手動構建路徑一樣,

一個節點的更好的API是Path module - 我會建議你readImages包裝是由通用readdir包裝,而是解決path.resolve數組「 d文件路徑

const readdir = dir => 
    new Task ((reject, resolve) => 
    fs.readdir (dir, (err, files) => 
     err 
     ? reject (err) 
     : resolve (files.map (f => path.resolve (dir, f))) 


const getImagesSizes = dir => 
    readdir (dir) .map (R.map (sizeOf)) 

包裝紙節點延續傳遞風格的API只是返回Task得到是一個麻煩,不是嗎?

const taskify = f => (...args) => 
    Task ((reject, resolve) => 
    f (...args, (err, x) => 
     err ? reject (err) : resolve (x))) 

const readdir = (dir, ...args) => 
    taskify (fs.readdir) (dir, ...args) 
    .map (R.map (f => path.resolve (dir, f))) 

const getImagesSizes = dir => 
    readdir (dir) .map (R.map (sizeOf)) 

你或許應該也照顧到文件指出,是目錄文件路徑 - 除非你sizeOf實現處理該

+1

我認爲大多數功能程序員都會將所有問題看作是一個「併發問題 - 不用擔心;那會隨着時間而改變 – naomik

+0

但是你所展示的也是一個構圖模式不是嗎?你能否擴展你的評論?我是FP的相對初學者,並且主要將FP學習爲一系列功能組合。 –

+1

阿米特,謝謝你強調了一個模棱兩可的問題 - 我打算區分*「[函數]組合」*和*「組合函數」本身 - 您可以查看所有複合函數作爲較小函數的組合,請記住,並非所有的函數組合都是用'compose'函數編寫的 - 所以是的,'readdir'是一個*組合*,但在這種情況下,'compose'函數並不能幫助我們更好地表達這個組合 - 大多數初學者會去「我需要一個作文「,達到」作曲「功能,然後想知道他們最終的節目爲什麼會感到尷尬。 – naomik

0

我設法通過將Task分辨率像一個單一的對象,以解決這個問題:

function readImages(path) { 
    return new Task(function(reject, resolve) { 
    fs.readdir(path, (err, images) => { 
     if (err) reject(err) 
     else resolve({ images, path }) 
    }) 
    }) 
} 

const withPath = task => { 
    return task.map(function({ images, path }) { 
    return images.map(getImagePath(path)) 
    }) 
} 

...然後破壞它的任務有效載荷和現在我的構建功能如下:

module.exports = (function getImageSize(dirPath) { 
    return compose(getSize, withPath, readImages) 
})() 

我的API調用看起來是這樣的:

getImageSize(portfolioPath).fork(
    function(error) { 
    throw error 
    }, 
    function(data) { 
    console.log(data) 
    } 
)