javascript - 如何重构这个命令式 JS 使其具有功能性?
问题描述
我尝试了一整夜,无法解决这个难题。代码,我想以功能方式重构:
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
ANDhtml
作为输入来将记录写入数据库,但是如果我在 之后将此函数放入管道中fetchHtml
,我只会得到html
. 还有更多 - 管道中的功能应该是一元的。{ url: 'http...', html: '<html>...' }
在将它传递给我之前,我应该以某种方式制作对象writeToCahce
吗?
2)我想使用 R.either 函数能够readFromCache
或者如果那里没有成功,请从网络管道转到我的 fetch (这也会将 html 保存在 db 中)。但是我的缓存读取函数返回 Promise。我可以使用R.pipeP
,但它似乎无法使用either
(R.either
继续第一个函数并返回 null。似乎它测试了 Promise 本身,因为它是真实值,它给了我对 pipeP 的承诺,它在那里解析为 null(缓存为空))
3)我尝试使用Task monad,但没有取得很大成功。我对这些概念还是陌生的
我觉得我做错了什么。很好奇它是怎么做到的
解决方案
我会使用一些来自瓦罐的助手以及闭包的魔力
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))
}
推荐阅读
- javascript - 在 JavaScript 中评估字符串时的错误
- firebase - 在 null 上调用了方法“[]”。接收方:null 尝试调用:[]("color")
- php - 重定向时会话未写入
- java - Spring boot和mySQL获取一对多关系的请求
- mysql - 如果是客户的第一个订单,计算订单日期
- html - 初学者:为什么HTML元素包括元素不调整高度
- c# - 将最大 400MB 大小的文件上传到 ASP.NET Core 3.1
- string - 如何将字符串转换为 rust 中的向量?
- python - 调用输入显示通道和用户参数
- c# - 我可以在 C# 中创建一个方法来尝试捕获一行代码吗?