Как реорганизовать этот императив JS, чтобы быть функциональным? - PullRequest
0 голосов
/ 25 сентября 2018

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

const R = require('ramda')
const axios = require('axios')
const Datastore = require('nedb')

const getDatastore = R.always(
  new Datastore({ filename: './cache.nedb', autoload: true }),
)

const writeHtmlToCache = R.curry((db, url, html) => {
  return new Promise((resolve, reject) => {
    db.insert({ url, html }, (err, doc) => {
      if (err) return reject(err)
      resolve(doc)
    })
  })
})

const readHtmlFromCache = R.curry((db, url) => {
  return new Promise((resolve, reject) => {
    db.findOne({ url }, (err, doc) => {
      if (err) reject(err)
      else resolve(doc)
    })
  })
})

const app = async url => {
  const db = getDatastore()
  let html = R.prop('html', await readHtmlFromCache(db, url))
  if (html) {
    console.log('loaded from cache', html.length)
    return html
  } else {
    html = R.prop('data', await axios.get(url))
    writeHtmlToCache(db, url, html)
    console.log('loaded from web', html.length)
    return html
  }
}

app('http://example.org/')

Проблемы, с которыми я столкнулся: 1) В функции writeToCache мне нужно url AND html в качестве ввода для записи записи в дб,но если я добавлю эту функцию в трубу после fetchHtml, я получу только html.И еще - функции в трубе должны быть одинарными.Должен ли я каким-то образом создать объект { url: 'http...', html: '<html>...' }, прежде чем передать его в моем writeToCahce?

2) Я хотел бы использовать функцию R.either, чтобы иметь возможность readFromCache ИЛИ, если там нет успеха, перейти к моей выборкеиз веб-канала (который также сохранит HTML в БД).Но моя функция чтения из кеша возвращает Promise.Я мог бы использовать R.pipeP, но, похоже, он не работает с either (R.either продолжается с первой функцией и возвращает ноль. Похоже, что он проверяет сам Promise и, поскольку это истинное значение, он дает мое обещание pipeP и там разрешаетсякак ноль (кеш пуст))

3) Я пытался играть с монадой задач, но с небольшим успехом.Я все еще новичок в этих понятиях

Мне кажется, я сделал что-то совершенно не так.Очень любопытно, как это можно сделать

1 Ответ

0 голосов
/ 25 сентября 2018

Я бы использовал несколько помощников из кроков вместе с магией замыканий

import unless from 'crocks/logic/unless'
import composeP from 'crocks/combinators/composeP'

const getDataWithUrl = url => () =>
  axios.get(url).then(R.prop('data')))

const writeWithDbAndUrl = (db, url) => html =>
  writeHtmlToCache(db, url, html)

const writeWhenNoHtml = (db, url) =>
  composeP(writeWithDbAndUrl(db, url), getDataWithUrl(url))

const app = url => {
  const db = getDatastore()
  return readHtmlFromCache(db, url)
    .then(unless(R.prop('html'), writeWhenNoHtml(db, url))
}
...