Welcome to the Swop 🎉🎉🎉
swop 是一个用于JavaScript
与客户端进行数据交互应用程序,他提供了简洁的api
来帮助开发者来做这些事情。
swop 的来源
在我们与客户端交互的时候,大量的数据散落在项目各个文件,或者集中于繁琐的redux
和window
对象之中,管理维护困难,操作麻烦,使得开发效率很低。
swop 要解决什么样的问题
swop 使用 aop
的理念进行设计开发,通过对于数据的拦截来做一些事情,swop 内置了中间件,参考一下express
和redux
的middleware
,但不同的是 swop 的middleware
没有next函数,swop 能让开发者更好的处理数据,更好的异步和错误处理。
API
options
swop 类 api
绑定属性 api
实例化 swop
swop 可以通过两种方式来实例化。
import { Swop, CreateSwop } from 'swop-data';
const S = new Swop(options);
const S = CreateSwop(options);
S.create('dataOne', 1);
S.dataOne.set(2).get();
如果你是用typescript
进行的开发
import {
Swop,
CreateSwop,
ContainerDataTypes as C,
} from 'swop-data';
export type A = C<I, keyof D>;
export type I =
'interfaceOne' |
'interfaceTwo';
export type D = {
'dataOne': A;
'dataTwo': A;
'dataThree': A;
}
const S = new Swop<I, D>(options);
S.creata('dataOne');
S.types.dataOne.get();
interface _Swop extends Swop<I, D>, D {}
const S = CreateSwop<_Swop>(options);
S.dataOne.get();
S['dataOne'].get();
swop 类 api
call
call 方法是于客户端进行通信的入口函数,他需要传入一个name字符和需要发送的数据。
S.call(name, data).then(([value, args]) => {
...
args.next();
}).catch(err => {
...
})
async function call_height () {
const data = await S.call(name, data)
...
}
S.call(name).then(([value, args]) => {
args.next(`上一次的响应值为:${value}`);
})
response
response 方法是客户端的入口函数。返回一个promise。
window.callback = data => S.response(data);
window.callback = data => {
S.response(data).then(_ => {
console.log('success');
}).catch(err => {
...
})
};
create
create 方法会创建一个绑定属性和绑定数据,返回值为this
。
S.create(attr_name, default_value, read_only)
.create(attr_name);
use
use 方法是 swop 提供的一个中间件函数,你可以通过 use 方法来注入一些中间件,中间件的注入与先后顺序相关,use 方法返回的是this
,所以你可以像 jQuery 那样链式调用。
S.use(name, val => {
if (typeof val.value === 'string') {
val.value = JSON.parse(val.value);
}
})
S.use(name, [value, match] => {
...
})
get_all_data
get_all_data 能够获取所有的绑定数据。
const all_data = S.get_all_data();
get_queue
swop 把当前接口的所有客户端响应都放到一个队列里面,get_queue 方法会返回当前接口的客户端响应队列。
const queqe = S.get_queue(name);
get_funs
当调用 call 方法与客户端进行数据交互时,会生成一个接收客户端响应的集合,每个集合由一个fun_body
和id
组成。get_funs 能够得到当前接口的所有集合。
const funs = S.get_funs(name);
const ids = funs.map(val => val.id);
ids.forEach((id, i) => {
S.response(JSON.stringify({
id,
origin_data: {
xx: 'xxx',
}
}))
})
clear_polling
clear_polling 方法清除绑定属性的轮询。如果name
为空,则清空所有绑定属性的轮询,返回值为this
。
S.clear_polling(name);
S.clear_polling();
绑定属性 api
当通过create
api 创建一个静态属性后,每个静态属性都会生成对应的方法,需要注意的是当生成的绑定数据是readOnly
时,当前绑定属性只有get
方法。
- 假定以下 api 描述的绑定属性名为 dataOne。
get
const data = S.dataOne.get();
set
set 方法会给当前绑定数据重新赋值,返回值是当前绑定属性
S.dataOne.set(1);
S.dataOne.set(1).get();
S.use('dataOne', val => val.value *= 100);
S.dataOne.set(1).get();
window.report = (data_name, data) => {
S[data_name].set(data);
}
当跟改数据时,虽然 swop 对榜单数据的值直接变动也能监听,但是正确的做法应该通过 set 方法来赋值。
S.dataOne.subscribe(new_value => {
...
})
S.get_all_data().dataOne = 1;
subscribe
subscribe 方法会对绑定数据进行监听,返回一个 remove 函数,用于注销当前的监听。
S.create('dataOne');
const remove = S.dataOne.subscribe((new_value, old_value) => {
document.body.innerHTML = new_value;
this.setState({
xx: new_value,
})
}, true);
remove();
unsubscribe
subscribe 方法会对绑定数据进行监听,需要手动一个个的注销掉监听,你会不会觉得太麻烦呢?unsubscribe 就是一个可以省事的 api,返回值为this
。
S.dataOne.unsubscribe();
polling
polling 会不停的对客户端进行 call,以此更新当前绑定数据的值,返回值为 stop 函数,用于终止轮询。
let interval;
function polling () {
const get = setInterval(async _ => {
const data = await S.call('interface', data);
S.dataOne.set(data);
if (S.get_funs().length < 50) { return; }
interval = setInterval(_ => {
if ( S.get_funs().length < 50) {
clearInterval(interval);
interval = null;
polling();
}
}, 100)
}, 100)
}
polling();
const stop = S.dataOne.polling('interfaceOne', '', data => {
...
});
stop();
S.dataOne.subscribe(new_value => {
this.setState({
xx: new_value,
})
})
S.dataOne.polling();
polling 方法在内部没有采用定时器的方法来轮询,所以不会带来大的内存开销。当返回的数据没有变动时候,polling 方法会降低轮询的频率,减少运行时的开销,关于清除所有绑定属性的轮询,可以看这里 clear_polling。
约定
swop 使用约定好的数据格式与客户端进行交互,这需要客户端的开发者配合。
在 JavaScript 层面,swop 会把数据转换成
{
origin_data: xxx(真正需要发送的数据),
id: xxx(swop 生成的一段随机字符数),
}
相应的,响应数据也应该保证统一的格式
{
origin_data: xx(真正需要响应的数据),
id: xx(swop 生成的id,id 是必须的),
}
id 和 origin_data 是唯一约定好的字段名,不应该带有其他的数据字段,不同的是,响应数据的格式是需要客户端的开发者手动转换成我们需要的格式,而 swop 会帮 JavaScript 开发者来做转换,id 是两者之间通信的凭证,swop 必须依靠 id 才能找到相应的响应集合。
如果响应数据的格式是 json,但在初始化实例的时候并没有让 swop 做 json 的解析,那么 swop 会通过正则表达式来截取真正需要的数据,需要注意带来的运行时开销。
绑定数据的更新也不应该通过 polling 函数来实现更新,客户端应该在数据发生变化时,数据上报给 JavaScript,通过绑定属性的 set 方法实现更新.