首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与Ramda一起使用Fluture

与Ramda一起使用Fluture
EN

Stack Overflow用户
提问于 2017-07-03 06:27:45
回答 2查看 1.9K关注 0票数 6

我使用Bluebird进行异步操作,但现在必须执行大量的空/空/错误检查,如果是其他路由,我不想继续执行。我想用单元组,但还没有完全摸索。

此外,我希望它能很好地处理ramda的pipe / compose,因为我的大多数其他代码都被巧妙地封装在功能管道中。根据许多 讨论的说法,一元期货(流场似乎是被推荐的)优先于承诺,对pipeP和composeP的支持在未来版本中可能会被删除。

Fluture似乎是一个很好的选择,因为它应该与坚持幻想-土地规格的库(比如ramda)玩得很好。

然而,对于如何实现Ramda的管道与Fluture的集成,我完全不知所措。我需要一些示例代码的帮助。

例如:

我有一个DB调用,它返回一个对象数组。数组可能有值、为空或未定义。我有一个函数管道来转换数据并将其返回到前端。

样本承诺代码:

代码语言:javascript
复制
fancyDBCall1(constraints)
  .then(data => {
    if (!data || data.length === 0) {
      return []
    }
    return pipe(
    ...
    transformation functions
    ...
    )(data)
  })
  .then(res.ok)
  .catch(res.serverError) 

有人能给我们指点一个好的方法吗。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-30 10:51:36

你能做什么?

所以,有几件事情可以用您的代码来完成。但首先,让我们来谈谈单子。

在这段代码中,您可以使用3种类型的Monad:

  • 也许( DB可能返回一些东西,或nothing )
  • 也可以(例如,如果某些数据验证失败)
  • (取代诺言)是与承诺不同的!)

也许这个,也许不是!

让我们对您的代码进行一点分解。我们要做的第一件事是确保fancyDBCall1(constraints)返回一个Maybe。这意味着它可能返回一个结果,或者什么也不返回。

但是,您的fancyDBCall1是一个异步操作。这意味着它必须返回一个Future。这里的诀窍是,不要让它返回一个值的未来,比如Future <Array>,让它返回一个Future < Maybe Array >

哇,听起来很复杂,先生!

把它想象成拥有:Future.of('world');

你有:Future.of( Maybe( 'world' ) );

没那么糟吧?

这样您就可以避免在代码中执行空检查!以下一行将消失:

代码语言:javascript
复制
if (!data || data.length === 0) {
  return []
}

你的例子应该是这样的:

代码语言:javascript
复制
/*
 * Accepts <Maybe Array>.
 * Most ramda.js functions are FL compatible, so this function
 * would probably remain unchanged.
 **/
const tranform = pipe( .... ); 

// fancyDBCall1 returns `Future <Maybe Array>`
fancyDBCall1(constraints)
  .map( transform )
  .fork( always(res.serverError), always(res.ok) );

看到我们的代码有多好了吗?但是等等,还有更多!

我们要么走得更远,要么不走!

所以,如果你密切关注的话,你就知道我错过了什么。当然,我们现在正在处理一个空检查,但是如果transform崩溃了怎么办?好吧,你会说“我们发送res.serverError”。

好的。当然行。但是,例如,如果transform函数由于用户名无效而失败怎么办?

你会说你的服务器爆炸了,但事实并非如此。你的异步查询很好,但是我们得到的数据却没有。这是我们可以预料到的,它不像流星击中我们的服务器场,只是一些用户给了我们一个无效的电子邮件,我们需要告诉他!

这里的诀窍是改变我们的transform函数:

代码语言:javascript
复制
/*
 * Accepts <Maybe Array>.
 * Returns <Maybe <Either String, Array> >
 **/
const tranform = pipe( .... ); 

哇天哪香蕉!这个黑魔法是什么?

在这里,我们说,我们的转换可能什么也不返回,或者它可能返回一个任。这要么是字符串(左分支总是错误),要么是值数组(右分支总是正确的结果!)

把所有的东西都放在一起

所以是的,这是一次非常糟糕的旅行,你说呢?为了给您提供一些具体的代码,让您深入了解,下面是一些使用这些构造的代码可能看起来是什么样子:

首先我们要和Future <Maybe Array>谈一谈

代码语言:javascript
复制
const { Future } = require("fluture");
const S = require("sanctuary");

const transform = S.map(
  S.pipe( [ S.trim, S.toUpper ] )
);

const queryResult = Future.of( 
  S.Just( ["  heello", "  world!"] ) 
);

//const queryResult2 = Future.of( S.Nothing );

const execute = 
  queryResult
    .map( S.map( transform ) )
    .fork(
      console.error,
      res => console.log( S.fromMaybe( [] ) ( res ) )
    );

你可以和queryResultqueryResult2一起玩。这应该给你一个很好的想法,也许单体可以做什么。

请注意,在本例中,我使用的是圣所,这是Ramda的一个纯粹版本,因为它可能是类型,但是您可以使用任何类型库,并且对它感到满意,代码的思想也是一样的。

现在,让我们添加任何一个。

首先,让我们集中讨论我们的转换函数,我对它做了一些修改:

代码语言:javascript
复制
const validateGreet = array =>
  array.includes("HELLO")       ?
  S.Right( array )    :
  S.Left( "Invalid Greeting!" );

// Receives an array, and returns Either <String, Array>
const transform = S.pipe( [
  S.map( S.pipe( [ S.trim, S.toUpper ] ) ),
  validateGreet
] );

到目前一切尚好。如果数组服从我们的条件,则使用数组返回任何一个的右分支,而不是带有错误的左分支。

现在,让我们将其添加到前面的示例中,该示例将返回一个Future <Maybe <Either <String, Array>>>

代码语言:javascript
复制
const { Future } = require("fluture");
const S = require("sanctuary");

const validateGreet = array =>
  array.includes("HELLO")       ?
  S.Right( array )    :
  S.Left( "Invalid Greeting!" );

// Receives an array, and returns Either <String, Array>
const transform = S.pipe( [
  S.map( S.pipe( [ S.trim, S.toUpper ] ) ),
  validateGreet
] );

//Play with me!
const queryResult = Future.of( 
  S.Just( ["  heello", "  world!"] ) 
);

//Play with me!
//const queryResult = Future.of( S.Nothing );

const execute = 
  queryResult
    .map( S.map( transform ) )
    .fork(
      err => {
          console.error(`The end is near!: ${err}`);
          process.exit(1);
      },
      res => {
        // fromMaybe: https://sanctuary.js.org/#fromMaybe
        const maybeResult = S.fromMaybe( S.Right([]) ) (res);

        //https://sanctuary.js.org/#either
        S.either( console.error ) (  console.log ) ( maybeResult )
      }
    );

这能告诉我们什么?

如果我们得到一个异常(一些意想不到的东西),我们打印The end is near!: ${err},然后干净地退出应用程序。

如果我们的DB没有返回任何内容,我们就打印[]

如果DB确实返回某项内容,并且该内容无效,则打印"Invalid Greeting!"

如果DB返回一些像样的东西,我们打印它!

耶稣香蕉,这可是太多了!

嗯,是的。如果你是从可能开始的,或者是,如果你有很多的概念需要学习,这是正常的,感到不知所措。

我个人不知道Ramda的任何好的和活跃的库,(也许您可以尝试使用民间故事中的可能/结果类型?)这就是为什么我使用了庇护所,一个来自Ramda的克隆,它更纯净,并且与Fluture很好地集成在一起。

但是,如果你需要从某个地方开始,你可以随时查看社区、聊天和发布问题。阅读文档也有很大帮助。

希望能帮上忙!

票数 12
EN

Stack Overflow用户

发布于 2017-07-03 14:52:44

不是专家,但既然专家不回答我想我可以帮上忙.;)

根据我的理解,您可以使用PromiseFuture来处理数据流的异步部分,使用MaybeEither来处理奇怪的/多个/null-data。

例如:您可以让数据转换函数处理null,如下所示:

代码语言:javascript
复制
const lengthDoubled = compose(x => x * 2, length);

const convertDataSafely = pipe(
  Maybe,
  map(lengthDoubled)
  // any other steps
);

然后,在您的Future中,您可以这样做:

代码语言:javascript
复制
Future(/* ... */)
  .map(convertDataSafely)
  .fork(console.error, console.log);

它将记录一个Nothing或包含一个整数的Just(...)

完整代码示例:(npm install ramdaflutureramda-fantasy)

代码语言:javascript
复制
const Future = require('fluture');
const Maybe = require('ramda-fantasy').Maybe;
const { length, pipe, compose, map } = require("ramda");

// Some random transformation
// [] -> int -> int
const lengthDoubled = compose(x => x * 2, length);

const convertData = pipe(
  Maybe,
  map(lengthDoubled)
)


Future(asyncVal(null))
  .map(convertData)
  .fork(console.error, console.log); // logs Nothing()


Future(asyncVal([]))
  .map(convertData)
  .fork(console.error, console.log); // logs Just(0)


Future(asyncVal([1,2,3]))
  .map(convertData)
  .fork(console.error, console.log); // logs Just(6)

Future(asyncError("Something went wrong"))
  .map(convertData)
  .fork(console.error, console.log); // Error logs "Something went wrong"

// Utils for async data returning
function asyncVal(x) {
  return (rej, res) => {
    setTimeout(() => res(x), 200);
  };
};

function asyncError(msg) {
  return (rej, res) => {
    setTimeout(() => rej(msg), 200)
  };
};

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44879042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档