nodejs createReadStream в функциональном программировании - PullRequest
0 голосов
/ 22 октября 2018

Я хотел бы получить ваши отзывы об использовании TaskEither с использованием fp-ts или другой библиотеки функционального программирования для учебных целей:

  • Я использую Promise при работе с потоком nodejs - это хорошее решение использовать Promise таким образом?Какие самые простые альтернативы?
  • Я использую .run().then(...) и .fold Знаете ли вы более лаконичный способ использования моей функции?
  • Можно ли переписать тот же код, используя Either без Promise?Не могли бы вы предоставить ма образец?

export const md5 = (path: string): TaskEither<string, string> => {
  const mkHash = (p: string) =>
    new Promise<string>((resolve, reject) => {
      const hash = createHash("md5");
      const rs = createReadStream(p);
      rs.on("error", (error: Error) => reject(error));
      rs.on("data", chunk => hash.update(chunk));
      rs.on("end", () => {
        return resolve(hash.digest("hex"));
      });
    });
  return tryCatch<string, string>(
    () => mkHash(path).then(x => x),
    message => `cannot create md5 hash: ${message}`
  );
};

it("should return right and create md5 hash for a file", () => {
    md5(fileName)
      .run()
      .then(e =>
        e.fold(console.log, r => {
          expect(r).toBe("SD8ddDad0756a93ded72b823b19dd877");
        })
      );
  });

  it("should return left with an error message", () => {
    md5(BAD_PATH)
      .run()
      .then(e =>
        e.fold(error => expect(error).toContain("ENOENT"), () => ({}))
      );
  });

Ответы [ 2 ]

0 голосов
/ 23 октября 2018

Я бы использовал Fluture для этой задачи.Это монадическая альтернатива ленивым вычислениям библиотеки обещаний, которая может переносить или генерировать обещания, но может работать в одиночку:

export const md5 = path =>
    Future ((reject, resolve) => {
      const hash = createHash ("md5")
      const rs = createReadStream (p)

      rs.on("error", reject);
      rs.on("data", chunk => hash.update (chunk));
      rs.on("end", () => {
        resolve (hash.digest ("hex"));
      })
    })
}

const eventualMd5 = md5('[path]')

Future.fork (console.error) (console.log) (eventualMd5)

В принципе, вы получаете лучшее из Either, используемое в асинхронных потоках, и многиесвязанные инструменты, чтобы раздвоить ваш код и обрабатывать как ошибки, так и сценарии успеха.

0 голосов
/ 22 октября 2018

Частичный ответ: мне удалось переписать эту функцию, используя только Either без Promise.Я все еще очень заинтересован в альтернативных решениях.

export const md5 = (path: string): Either<string, string> => {
  const BUFFER_SIZE = 8192;
  let fd;
  try {
    fd = openSync(path, "r");
    const buffer = Buffer.alloc(BUFFER_SIZE);
    const hash = createHash("md5");
    let bytesRead;
    do {
      bytesRead = readSync(fd, buffer, 0, BUFFER_SIZE, 0);
      hash.update(buffer.slice(0, bytesRead));
    } while (bytesRead === BUFFER_SIZE);
    return right(hash.digest("hex"));
  } catch (error) {
    return left(error.message);
  } finally {
    if (fd !== undefined) {
         closeSync(fd);
    }
  }
};

  it("should return right and create md5 hash for a file", () => {
    const mk = md5(fileName);
    assert.strictEqual(mk.isLeft(), false);
    assert.strictEqual(mk.isRight(), true);
    assert.strictEqual(mk.value, "SS8dd3ad07e6a93ded72b823b19dd877");
  });

  it("should return left return an error message", () => {
    const mk = md5(BAD_PATH);
    assert.strictEqual(mk.isLeft(), true);
    assert.strictEqual(mk.isRight(), false);
    assert.strictEqual(mk.value.includes("ENOENT"), true);
  });
...