如何使用Ramda.js重构这个组合函数?

时间:2017-10-20 09:07:02

标签: javascript node.js functional-programming ramda.js

我正在使用ramdadata.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两次传入directoryName:一次用于读取文件,第二次用于读取路径。这意味着我必须像这样调用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)
  }
)

2 个答案:

答案 0 :(得分:1)

你不应该像那样手动构建路径

Node的更好的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))

包装Node延续传递样式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 :(得分: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))
  })
}

...然后将其从任务有效负载中删除,现在我的compose函数如下所示:

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

我的api电话看起来像这样:

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