异步函数请求堆栈-解决页面多并发问题
本帖最后由 dexteryao 于 2021-4-25 10:56 编辑SpreadJS提供了异步函数的功能,可以让函数通过调用API异步获取数据。但是当页面上使用的异步函数较多,刷新计算时会同时发生大量的网络请求,不仅给服务器造成压力,也会由于异步函数的同时更新造成页面的频繁刷新,影响用户体验。
为了解决这个问题,我们可以采用请求堆栈的方式,收集函数请求,统一发送网络请求并一次更新。
具体更新时机机制可以根据我们业务需求决定,下面以定时请求为例说明具体实现。
当第一个请求发生1秒后,发起一次网络请求。1秒内有其他请求进入就收集进堆栈,后续请求放入下一个堆栈,以此类推。
下面代码是一个普通异步函数GETNUMBERFROMSERVER的实现,调用getData接口(模拟接口直接返回arg1数据,未做其他处理),传递参数,获取显示内容并展示在单元格。
var GetNumberFromServer = function () {
};
GetNumberFromServer.prototype = new GC.Spread.CalcEngine.Functions.AsyncFunction("GETNUMBERFROMSERVER", 1, 2);
GetNumberFromServer.prototype.evaluate = function (context, arg1, arg2) {
fetch("/spread/getData?data="+arg1)
.then(function(response) {
return response.text();
})
.then(function(text) {
context.setAsyncResult(text);
});
};
GC.Spread.CalcEngine.Functions.defineGlobalCustomFunction("GETNUMBERFROMSERVER", new GetNumberFromServer());
为了减少请求,我们使用一个缓存对象存放请求数据,定时调用接口处理
let callStack = {}; //收集请求数据
let callingStack = {}; //缓存正在请求中的数据信息
let callStackCount = 0; //请求数量,当作请求ID,用于区分请求内容
let timingId = 0; //用于判断当前是否有定时器等待请求中
定义请求方法,代替再函数中直接调用API接口
// data 请求数据
// context 异步函数context, 网络请求结束后回调时使用
// callback 回调函数
function stackCall(data, context, callback){
let id = callStackCount++;
callStack = {};
callStack.data = data;
callStack.context = context;
callStack.callback = callback;
if(timingId === 0){ // 同时只有一个定时器
timingId = setTimeout(function(){
callingStack = callStack;
callStack = {};
let newData = "" //合并请求数据,根据实际业务情况整理
for(let cId in callingStack){
newData += (cId + "," + callingStack.data + ";");
}
// 发送请求,这里模拟数据,发送什么返回什么
fetch("/spread/getData?data=" + newData)
.then(function(response) {
return response.text();
})
.then(function(text) {
let resData = newData.split(";");
let spread = designer.getWorkbook();
spread.suspendPaint(); //暂定页面绘制
//解析返回的数据
for(let resId in resData){
if(resData){
let ress = resData.split(",");
// 根据Id,获取函数的context,调用callback回调
callingStack].callback.call(null, callingStack].context, ress)
}
}
spread.resumePaint(); //重启统一绘制
timingId = 0;
});
}, 1000)
}
}
更新异步函数实现方式,函数中调用stackCall堆栈函数,批量调用成功后执行callback回调中的setAsyncResult方法。
GetNumberFromServer.prototype.evaluate = function (context, arg1, arg2) {
stackCall(arg1, context, function(context, text){
context.setAsyncResult(text);
})
};
通过以上实现,当页面有大量异步请求时会统一处理,一次刷新。
另外还可以使用doNotRecalculateAfterLoad导入选项,在首次加载时不计算,使用json中原始值,以及calcOnDemand开启按需计算。
这两个option可以根据您的实际需求设置。
json.calcOnDemand = true;
spread.fromJSON(json, { doNotRecalculateAfterLoad: true });
本帖最后由 athenadeveloper 于 2022-10-14 16:52 编辑
请教一下,代码中的处理返回数据段,如附件图。从代码来看是在拆分请求数据,此处是不需要拿到api的返回数据来做处理吗?
收到问题,这边调研下给您回复。 athenadeveloper 发表于 2022-10-14 11:15
请教一下,代码中的处理返回数据段,如附件图。从代码来看是在拆分请求数据,此处是不需要拿到api的返回数 ...
想请教一下版主 如果异步函数的调用这些代码是放在js文件里面的那这个方法里面的 designer有办法传进去吗用的技术栈是vue2+v16 文章中designer指的是designer(设计器)对象,您初始化deisgner获取对象后,就可以做后续的处理了。
Lynn.Dou 发表于 2023-4-17 18:13
文章中designer指的是designer(设计器)对象,您初始化deisgner获取对象后,就可以做后续的处理了。
再想请教下版主,如果定义了多个异步函数,sheet中也存在多个异步公式,触发计算时,这个函数应该如何改造,并且需要在所有异步公式计算完成后给用户一个计算完成的提示
页:
[1]