为什么R.ifElse没有回复承诺?

时间:2017-12-13 15:36:09

标签: javascript csv promise ramda.js

任务

我需要创建一个应用程序来读取CSV文件,转换其数据,然后将其作为另一个CSV文件输出。

输入格式如下:

13:25:37 up 19 days, 21:35,  4 users,  load average: 0.02, 0.02, 0.00
13:25:38 up 19 days, 21:35,  4 users,  load average: 0.02, 0.02, 0.00
... so on

对于那些UNIX粉丝的用户,您会将其识别为控制台命令uptime的输出。

我想要的输出格式如下:

 RowNum, Avg Load
 1,0.02
 2,0.02

第一列是CSV中的行号,第二列是平均负载的数字部分:0.02。

要忽略所有其他列。

问题

尽可能在功能上尝试这样做,我决定使用ramda

至少可以说这是一个挑战。现在,我的代码有几个结构问题,但我想关注main函数,它不起作用。每次执行代码时都会收到错误:

index.js:54
    .then( () => console.log("Done!") )
     ^

TypeError: main(...).then is not a function

这令人困惑,因为在我传递给R.ifElse的两个函数中,我都返回了一个Promise。

代码

const fs = require("fs");
const csvReader = require("csvreader");
const R = require("ramda");
const isString = require("lodash.isstring");
const { promisify } = require("util");
const argv = require("minimist")(process.argv.slice(2));
const appedFileAsync = promisify( fs.appendFile );

const createProcessData = () => {
    const stringifyArray = array => `${array.toString()}\n`;
    const write = str => fs.appendFileSync( argv.outputFile, str );

    const getAvg = R.pipe(
        R.replace("load average:", ""),
        R.trim
    );

    let elapsedTime = 1;
    const transform = list => [ elapsedTime++, getAvg ( R.nth( 3, list ) ) ];

    return R.pipe(
        transform,
        stringifyArray,
        write
    );
};

const printHelp = () => {
    console.log(`
        === MAN HELP ===
        Usage: npm start -- --inputFile input.csv --outputFile output.csv
        --inputFile: location of an input file in CSV format
        --outputFile: location of an output file to append the new information to.
        If this file does not exist, it will be created.
    `);
    return Promise.resolve();
};

const execute = () => appedFileAsync( argv.outputFile, "Time, Avg Load\n" )
    .then( ( ) => csvReader.read( argv.inputFile, createProcessData() ) );

const main = () => {
    const isInvalidFileName = R.anyPass( [ R.isNil, R.isEmpty, R.pipe ( isString, R.not ) ] );
    const hasInvalidArgs = R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) );

    return R.ifElse(
        hasInvalidArgs,
        printHelp,
        execute
    );
};

main()
    .then( () => console.log("Done!") )
    .catch( console.error );

问题

  • 我的代码出了什么问题?

1 个答案:

答案 0 :(得分:2)

这是考虑ifElse

的方法
const ifElse = (predicate, consequent, alternative) => 
    (...val) => predicate(...val) ? consequent(...val) : alternative(...val);

所以

const comp = ifElse(
  (a, b) => a < b,
  (a, b) => `${a} is smaller than ${b}`,
  (a, b) => `${a} is at least as large as ${b}`
)

comp(12, 7) //=> "12 is at least as large as 7"

重点是ifElse的第一个参数是函数。但是你传递了它的结果:

R.either( isInvalidFileName( argv.inputFile ), isInvalidFileName( argv.outputFile ) )

现在通常,either会返回一个函数。但这取决于你向它提供功能。假设如果您不提供函数,您就知道自己在做什么,并且正在使用apmap方法提供容器类型,因此either稍微更通用。但是你提供的布尔值是isInvalidFileName( argv.inputFile )的结果。那时行为没有明确定义。也许这应该改变,但Ramda的哲学通常是垃圾垃圾。因此无论出于何种原因,either调用都会返回[undefined]

这意味着您将[undefined]作为谓词函数提供给ifElse。当您尝试调用它时,您应该收到错误。我没有试图追查为什么那个错误被你看到的错误所掩盖。

至于如何使用Ramda解决这个问题,我不确定从哪里开始。这与Ramda一贯的风格相差甚远。如果没有别的,那些不接受参数的函数在Ramda中极为罕见。我想我会用一个接受argv.inputFileargv.outputFile的函数启动Ramda部分,作为单个对象或者可能作为单个对象argv