function library
npm install @szmg-fe/funba
Funba基于ramda、data.task、lodash的函数式编程应用库,核心围绕Task,通过curry&compose提供point free的代码风格,同时提供一些utils函数,Funba已通过jest覆盖单元测试
你可能需要熟悉
- ramda
- data.task
- lodash
import ap from 'funba/ap';
import Task from 'funba/task';
import {compose} from 'funba/ramda'
import fork from 'funba/fork'
import {log, error} from 'funba/console'const add = new Task(function (reject, resolve) {
setTimeout(function () {
resolve(function (x) {
return x + 1;
});
}, 1000);
});
const multiply = new Task(function (reject, resolve) {
setTimeout(function () {
resolve(function (x) {
return x * 10;
});
}, 5000);
});
const value = new Task(function (reject, resolve) {
setTimeout(function () {
resolve(1);
}, 1000);
});
const calculateValue = compose(fork(error, log), ap(value));
calculateValue(add); // 2
calculateValue(multiply); // 10
`
$3
ap的高阶应用 - 并发处理相当于Promise.all
`
import createAction from 'funba/actionCreater';
import {compose} from 'funba/ramda'
import {error, log} from 'funba/console'
import all from 'funba/all';const action = createAction(error);
const createTaskByNumber = n => new Task((rej, res) => {
setTimeout(() => res(n), n * 1000);
});
const [http1, http3, http5] = [1, 3, 5].map(n => createTaskByNumber(n));
const http135 = compose(action(log), all([http1, http3, http5]);
http135((x, y, z) => x + y + z); // 9
`$3
concat的高阶应用,处理并发竟态
`
const action = createAction(log);const createTaskByNumber = n => new Task((rej, res) => {
setTimeout(() => res(n), n * 1000);
});
const [http1, http3, http5] = [1, 3, 5].map(n => createTaskByNumber(n));
compose(action(log), race)([http1, http3, http5]); // log 1
`$3
分别处理一个函子中的reject和resolve
`
import Task from 'funba/Task';
import { compose } from 'funba/ramda';
import bimap from 'funba/bimap';
import fork from 'funba/fork';
import {error, log} from 'funba/console'const cfTask = n => new Task((rej, res) => {
if (n >= 5) {
res(n)
} else {
rej(n)
}
});
compose(fork(error, log), bimap(x => x + 1, x => x - 1), cfTask)(5); // log - 4
compose(fork(error, log), bimap(x => x + 1, x => x - 1), cfTask)(2); // error - 3
`$3
串联执行task
`
const cfTask = n => new Task((rej, res) => {
res(n);
});const add = x => new Task((rej, res) => {
res(x + 5);
});
const mutiply = x => new Task((rej, res) => {
res(x * 5);
});
compose(fork(error, log),chain(mutiply), chain(add), cfTask)(5); // 50
`
$3
分别作用于函子的reject和resolve,并在外部的resolve获取bimap的不同点在于 bimap可以在reject中获取f作用的value
`
const cfTask = n => new Task((rej, res) => { if (n >= 5) {
res(n)
} else {
rej(n)
}
});
compose(fork(error, log), fold(x => x + 1, x => x - 1), cfTask)(5); // log 4
compose(fork(error, log), fold(x => x + 1, x => x - 1), cfTask)(2); // log 3
`$3
Task的执行api
`
import fork from 'funba/fork';
import Task from 'funba/Task';
import {error} from 'funba/console';new Task((rej) => rej(1)).fork(error); // error 1;
`$3
将参数直接返回
`
import id from 'funba/id';id(2) === 2;
id(true) === true
`$3
Task生成器
`
import of from 'funba/of'
of(1) === new Task((rej, res) => res(1));
`
$3
rejectedMap反向的map
`
new Task((rej) => rej(1)).rejectedMap(x => x + 5).fork(error); // error 6
`
$3
反向的chain,作用在task的reject
`
const cfTask = n => new Task((rej, res) => { if (n >= 5) {
res(n)
} else {
rej(n)
}
});
const add = n => new Task((rej, res) => {
rej(n + 5);
})
const multiply = n => new Task((rej, res) => {
rej(n * 5);
})
const multiply2 = n => new Task((rej, res) => {
res(n * 8);
})
compose(fork(error), orElse(multiply), orElse(add), cfTask)(1); // error 30
`
$3
快速生成一个action - 封装fork(f, g)行为
`
import createAction from 'funba/createAction';
import {compose} from 'funba/ramda'
import {error, log} from 'funba/console'const action = createAction(error);
const throwErr = n => new task((rej) => rej(n));
const run = compose(action(log), throwErr);
run(5); // error 5
`$3
api生成器
`
import api from 'funba/createApi';
import axiosHttp from 'funba/axiosHttp';const axiosApi = api(axiosHttp);
const mockData = {'/api/login': {name: 'lemon'}};
const baiduApi = axiosApi('https://www.baidu.com' , mockData);
// 开启mock之后GetHttp&PostHttp都会返回mock数据
// Mock始终返回mock数据
const {
GetHttp,
PostHttp,
Mock
} = baiduApi(true);
// 同一个项目有非常多的api host的话
const baiduApi = axiosApi('https://www.baidu.com' , mockData);
const wxApi = axiosApi('https://www.wx.com' , mockData);
const alibabaApi = axiosApi('https://www.alibaba.com' , mockData);
`$3
类似于curry 将一个函数携带值去应用
`
import bringFunction from "funba/bringFunction";
const add = x => x + 1;
const _add = bringFunction(add);
const _add1 = _add(1);
_add1(); // 2
`$3
将参数传入一组函数使用,参数依次进行传递
`
import applyFunction from 'funba/applyFunction'
const data = {
count: 0
};
const add1 = data => data.count+=1;
const add3 = data => data.count+=3;
const add5 = data => data.count+=5;
const app = applyFunction([add1, add3, add5]);app(data); // data.count === 9
`$3
提供一个封装了axios的api
`
import axiosApi from 'funba/axiosApi'
const baiduApi = axiosApi('https://www.baidu.com', {});
const {
GetHttp,
PostHttp,
Mock
} = baiduApi(true); // 开启mock
`$3
提供了一个封装了axios的task,也可以直接使用axiosApi
`
import axiosHttp from 'funba/axiosHttp';
import fork from 'funba/fork';
import {log, error} from 'funba/console';const sayHi = compose(fork(error, log), axiosHttp);
sayHi('www.baidu.com', 'get', '/api/sayHi', 'lemon');
`$3
运行一个函数,但是返回参数
`
import backArgs from 'funba/backArgs';const a = {
count: 1
};
const b = {
count: 2
}
const add = backArgs(x => b.count = b.count + x.count);
add(a) === a // true
`$3
检查空字符
`
import checkSpace from 'funba/checkSpace';
checkSpace('') // true
`$3
将一个对象转换成query string
`
import createParamsString from 'funba/createParamsString';createParamsString({a: 1, b: 2}) === '?a=1&b=2';
`$3
提供轻量级的时间格式化工具
`
import {dateFormat_yy_mm_dd} from 'funba/date';
dateFormat_yy_mm_dd(Date.now()); // 2021-12-01;
`$3
转换成反布尔值
`
import invertBoolean from 'funba/invertBoolean';
invertBoolean(1) === false
`$3
接收一个mockdata对象 返回一个mock请求Task
`
// createApi源码部分
const mockHttpApi = mock(mockData); // 直接返回一个mock
const curryMockHttpApi = curry(mockHttpApi);
const getMockHttp = curryMockHttpApi(server, 'GET');
const Mock = (url: string) => compose(getMockHttp(url), id); // mock请求
`
$3
收集mockData
`
const loginMock = {
'/api/login': {name: 'lemon'}
}const articleMock = {
'/api/getList': []
};
const mockData = createMockData(); // createMockData可以接收一个格式化函数
const allMockData = mockData(
loginMock,
articleMock
);
`$3
接收一个Promise,让这个promise始终有返回值
`
const a = async () => packPromise(new Promise((res, rej) => { setTimeout(() => res(5), 2000);
}));
const [res, err] = await a(); // res 5 , err undefined
`$3
获取属性
`
import prop from 'funba/prop';
prop('key', {key: 1}); // 1
`$3
函数组合, 来自ramda
`
import {compose} from 'funba/ramda'
`
$3
函数柯里化, 来自ramda
`
import {curry} from 'funba/ramda'
`
$3
map方法,既可以处理函子也可以处理数组, 来自ramda
`
import {map} from 'funba/ramda'
`
$3
concat, 来自ramda
`
import {concat} from 'funba/ramda'
`$3
head,取出数组第一项, 来自ramda
`
import {head} from 'funba/ramda'
`$3
一定范围内的随机数
`
import selectNum from 'funba/selectNum';
selectNum(0, 10); // 5
`$3
柯里化字符串替换
`
import replace from 'funba/replace';
const replaceSpace = replace(regSpace, '');
replaceSpace('12 43 45'); // 124345
`$3
log请求日志$3
compose中的断点工具
`
compose(log, trace('after error'), error)
`$3
操作localStorage
`
const saveStorage = setLocalStorage('user');
saveStorage({name: 'lemon'});getLocalStorage('user'); => {name: 'lemon'}
`
$3
判断是否为微信内Test
`
yarn test
yarn report
``