有没有办法在内部写一个Maybe.map的承诺?

我正在关注这篇优秀文章的前半部分,但是有一个地方我被困住了。 https://jrsinclair.com/articles/2016/marvellously-mysterious-javascript-maybe-monad/

我已经实现了一个非常相似的Maybe monad,但是我需要传递给map的一个函数是asynchronous的。 理想情况下,我可以在.then()和map()的组合中做到这一点。 我想要做这样的事情…

const getToken = async (p) => { let result = utils.Maybe.of(await makeAICCCall(p.aiccsid, p.aiccurl)) .map(parseAuthenticatedUser) .thenMap(syncUserWithCore) <-- I can't figure this out .map(managejwt.maketoken) .value return result; } 

我已经尝试过所有我能想到的事情,但是我一直无法弄清楚这一点。

自然转化

数据容器的嵌套可能会变得杂乱无章,但是有一个众所周知的保持平坦的技术 – 下面的“ eitherToPromise被认为是一种自然的转换 – 它将一个“任一”转换成一个允许它在链中被展平的“承诺”,而且同时防止你的价值/错误导线越过

注意:您可能想要使用makeAICCall来返回一个EitherLeftRight )而不是Maybe因为您将能够返回一个错误消息(而不是Nothing ,这是不太有用的信息)

 import { Left, Right, eitherToPromise } from './Either' const makeAICCall = (...) => someCondition ? Left (Error ('error happened')) : Right (someResult) const getToken = p => makeAICCall (p.aiccsic, p.aiccurl) // => Promise<Either<x>> .then (eitherToPromise) // => Promise<Promise<x>> // => auto-flattened to Promise<x> .then (syncUserWithCore) // => Promise<x> .then (managejwt.maketoken) // => Promise<x> 

提供您最喜爱的执行Either

 // Either.js export const Left = x => ({ fold: (f,_) => f (x), // map: f => Left (x), // chain: ..., // ... }) export const Right = x => ({ fold: (_,f) => f (x), // map: f => Right (f (x)), // chain: ..., // ... }) export const eitherToPromise = m => m.fold (x => Promise.reject (x), x => Promise.resolve (x)) 

可运行的演示

 const someAsyncCall = x => new Promise (r => setTimeout (r, 1000, x)) const authenticate = ({user, password}) => password !== 'password1' ? Left (Error ('invalid password')) : Right ({user, id: 123}) const someSyncCall = token => Object.assign (token, { now: Date.now () }) const getToken = x => someAsyncCall (x) .then (authenticate) .then (eitherToPromise) .then (someSyncCall) // minimal dependencies const Left = x => ({ fold: (f,_) => f (x) }) const Right = x => ({ fold: (_,f) => f (x) }) const eitherToPromise = m => m.fold (x => Promise.reject (x), x => Promise.resolve (x)) // test it getToken ({user: 'alice', password: 'password1'}) .then (console.log, console.error) // 1 second later ... // { user: 'alice', id: 123, now: 1509034652179 } getToken ({user: 'bob', password: 'password2'}) .then (console.log, console.error) // 1 second later ... // Error: invalid password ... 
Interesting Posts