使用ECharts
的lazyUpdate
模式多次执行setOption
,仅对最终的option
渲染一次。ECharts
是和React
一致自己单独实现了一套任务管理机制,还是基于setTimeout
或Promise
做的异步渲染?我们尝试从ECharts的源码中来一探究竟。
极好定位这里不再赘述
setOption<Opt extends ECBasicOption>(option: Opt, notMerge?: boolean | SetOptionOpts, lazyUpdate?: boolean): void {
if (__DEV__) {
assert(!this[IN_MAIN_PROCESS_KEY], '`setOption` should not be called during main process.');
}
if (this._disposed) {
disposedWarning(this.id);
return;
}
let silent;
let replaceMerge;
let transitionOpt: SetOptionTransitionOpt;
if (isObject(notMerge)) {
lazyUpdate = notMerge.lazyUpdate;
silent = notMerge.silent;
replaceMerge = notMerge.replaceMerge;
transitionOpt = notMerge.transition;
notMerge = notMerge.notMerge;
}
this[IN_MAIN_PROCESS_KEY] = true;
if (!this._model || notMerge) {
const optionManager = new OptionManager(this._api);
const theme = this._theme;
const ecModel = this._model = new GlobalModel();
ecModel.scheduler = this._scheduler;
ecModel.init(null, null, null, theme, this._locale, optionManager);
}
this._model.setOption(option as ECBasicOption, { replaceMerge }, optionPreprocessorFuncs);
const updateParams = {
seriesTransition: transitionOpt,
optionChanged: true
} as UpdateLifecycleParams;
// 批量更新、懒更新 标记
if (lazyUpdate) {
this[PENDING_UPDATE] = {
silent: silent,
updateParams: updateParams
};
// 这里把 主进程状态置为了 false
this[IN_MAIN_PROCESS_KEY] = false;
// this.getZr()直接返回了 zrender 对象 接下来看zrender的wakeUp方法(唤醒动画渲染)
this.getZr().wakeUp();
}
else {
prepare(this);
updateMethods.update.call(this, null, updateParams);
// 如果不是懒更新则直接flush图像
this._zr.flush();
this[PENDING_UPDATE] = null;
this[IN_MAIN_PROCESS_KEY] = false;
flushPendingActions.call(this, silent);
triggerUpdatedEvent.call(this, silent);
}
}
wakeUp() {
// 这里启动了动画渲染
this.animation.start();
// Reset the frame count.
this._stillFrameAccum = 0;
}
/**
* Start animation.
*/
start() {
if (this._running) {
return;
}
this._time = new Date().getTime();
this._pausedTime = 0;
// 开启渲染动画
this._startLoop();
}
_startLoop() {
const self = this;
this._running = true;
// 渲染帧
function step() {
if (self._running) {
requestAnimationFrame(step);
!self._paused && self.update();
}
}
requestAnimationFrame(step);
}
代码挺好跟,但涉及到Even loop
深入理解起来会相对困难。简单说明就是采用lazyUpdate
更新图表的话,图表会在下一个 animation frame
中更新而在下一个animation frame
之前执行的setOption
会根据notMerge
参数来判断是合并option
还是采用最后一次option
直接渲染。
requestIdleCallback和requestAnimationFrame详解
Renderer Process Compositor Thread Compositor Tile Worker(s) Main Thread GPU Thread GPU Process Input event handlers requestAnim- ationFrame Parse HTML Recalc Styles Layout Update Layer Tree Paint Frame Start Composite Raster Scheduled Rasterize Frame End requestIdleCallback Layer tiles uploaded to GPU and composited. vsync and input data commit commit