2017-10-20 41 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) 
    } 
)