【问题标题】:Conditional with promise in Ramda在 Ramda 中以 promise 为条件
【发布时间】:2018-03-17 09:40:15
【问题描述】:

如何将R.cond 与承诺一起使用?

类似这样的..

const fetchBin = (url) => fetch(`https://httpbin.org${url}`).then((response) => {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
})

const testStatus = (status) => fetchBin(`/status/${status}`);

const isOk = R.propEq('statusCode', 200);
const testCond = R.cond([
    [ R.pipeP(testStatus, isOk), (resp) => console.log('The resp is ', resp) ],
    [ R.T, (code) => console.log('The resp is NOT ok', code) ]
])

testCond(404)
// R.pipeP(testStatus, isOk)(404)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>

【问题讨论】:

  • 我认为你应该在 thentestStatus 中包含 testCond 部分,因为根据 Ramda 文档,谓词应该是 cond 中的纯函数。

标签: javascript functional-programming promise ramda.js


【解决方案1】:

我认为这就是您所追求的,通过将其与 testStatus 组合,您应该能够获取 response 对象并进行条件分支。

const fetchBin = (url) => fetch(`https://httpbin.org${url}`).then((response) => {
    var contentType = response.headers.get("content-type");
    if(contentType && contentType.includes("application/json")) {
      return response.json();
    }
    throw new TypeError("Oops, we haven't got JSON!");
})

const testStatus = (status) => fetchBin(`/status/${status}`);

const isOk = R.propEq('statusCode', 200);
const testCond = R.pipeP(testStatus, R.cond([
  [isOk, resp => console.log('The resp is OK :' + resp.statusCode)],
  [R.T, resp => console.log('The resp is NOT OK :' + resp.statusCode)]
]));

testCond(404)
// R.pipeP(testStatus, isOk)(404)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.24.1/ramda.min.js"></script>

【讨论】:

  • 嗨@MinusFour,我尝试了你的建议,但没有奏效。 R.pipeP(testStatus, /* If the promise is not resolved (catch in this case) the condition are not executed */)可以查看here
  • 如果你依赖于 catch 子句,那将是一个问题,即使它拒绝,你也必须履行承诺。我的印象是,即使是 400 个状态码,您也会返回一个带有 400 个状态码属性的 JSON 答案。
【解决方案2】:

全新视角

提醒自己,我们应该成为改变我们编程语言的人,而不是相反

在我看来,您似乎走错了路。 fetchBin 是我们真正要找的那个人的稻草人。我们需要一个接收 URL 并返回解析后的 JSON 响应的函数;我们就叫这个人吧,fetchJSON

从那里,我们使用fetchJSON 实现fetchBin - 无论资源返回404 状态还是带有错误内容类型的200 状态(参见下面的XML 示例) - 要么方式,promise 将被正确路由到错误处理程序(下面的console.error;或者.then(console.log).catch(console.error))——这里的重点是,如果我不清楚,fetchBin 不应该关心像什么这样的细节HTTP 状态码是什么,或者响应的 Content-Type 标头可能是什么——只要让它请求解析的 JSON,就不用担心其余的了

我分享这个的原因是为了帮助您避免陷入特定的思维方式。 R.cond 是一个非常糟糕的形式,如果我们完全诚实的话——它会迫使你调整程序分支的语义,方法是将它限制在一个数组中并创建 thunk 来保存可能的条件分支永远不要被你的程序使用; true 惰性仅在使用 if/else?: 的严格评估的 JavaScript 中可用;没有他们,你仍然在做不必要的工作

一旦我们从像R.cond 这样的僵化形式中解脱出来,事情就会自然而然地结合在一起——哎呀,我们甚至根本不需要R.pipeR.pipePR...

const fetchJSON = url =>
  fetch (url)
    .then (responseOK)
    .then (parseJSON)

const responseOK = (response) =>
  {
    if (response.status >= 200 && response.status < 300)
      return response
    else
      throw Object.assign (Error (response.statusText), { response })
  }

const parseJSON = response =>
  response.json ()
    
const fetchBin = (url) =>
  fetchJSON ('https://httpbin.org' + url)

fetchBin ('/anything?a=b') .then (console.log, console.error)
// all things good !
// => { args: {a: 'b'}, data: '' ... }

fetchBin ('/status/404') .then (console.log, console.error)
// non-200 status goes to error handler
// => { Error: NOT FOUND ..., response }

fetchBin ('/xml') .then (console.log, console.error)
// bad JSON goes to error handler
// => SyntaxError: Unexpected token < in JSON at position 0

好的,所以我们在那里不需要R,但这个答案并不意味着暗示这是一般的经验法则。 Ramda 是一个很棒的工具,可以教你很多关于函数式编程的知识——只要记住有时退一步,评估你的程序是否可以用你想要的方式表达,而不是担心语言(或库,或函数;R.cond)想要

【讨论】:

    猜你喜欢
    • 2020-04-27
    • 2019-10-30
    • 2019-04-15
    • 2017-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多