如何用 Ramda.js 重构这个组合函数?
How do I refactor this composed function with Ramda.js?
我正在使用 ramda
和 data.task
编写一个小实用程序,它可以从目录中读取图像文件并输出它们的大小。我是这样工作的:
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)
}
)
我设法通过将 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)
}
)
你不应该像那样手动构建路径
Node 的一个更好的 API 是 Path module – I would recommend that your readImages
wrapper is made a generic readdir
wrapper, and instead resolve an Array of path.resolve
的文件路径
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))
将 Node continuation-passing 风格的 API 包装成 return 一个 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
实现处理
我正在使用 ramda
和 data.task
编写一个小实用程序,它可以从目录中读取图像文件并输出它们的大小。我是这样工作的:
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)
}
)
我设法通过将 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)
}
)
你不应该像那样手动构建路径
Node 的一个更好的 API 是 Path module – I would recommend that your readImages
wrapper is made a generic readdir
wrapper, and instead resolve an Array of path.resolve
的文件路径
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))
将 Node continuation-passing 风格的 API 包装成 return 一个 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
实现处理