Commit 04fedfc7 authored by 杨贺晨吉's avatar 杨贺晨吉

Merge branch 'opt' into 'master'

Opt

See merge request !2
parents cb399e5b bceff57e
{ {
"name": "@tuia/rip", "name": "@tuia/rip",
"version": "0.2.0", "version": "0.2.1",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
......
{ {
"name": "@tuia/rip", "name": "@tuia/rip",
"version": "0.2.1", "version": "0.2.2",
"description": "Tools for user behavior recording and playback based on rrweb", "description": "Tools for user behavior recording and playback based on rrweb",
"main": "dist/index.js", "main": "dist/index.js",
"scripts": { "scripts": {
......
...@@ -31,7 +31,7 @@ class Monitor { ...@@ -31,7 +31,7 @@ class Monitor {
this.tracksWorker.onmessage = (event) => { this.tracksWorker.onmessage = (event) => {
switch(event.data) { switch(event.data) {
case "resetRecord": case "resetRecord":
this.record(); this.record(); // 开启录制
break; break;
default: default:
console.log("unknow action", event.data); console.log("unknow action", event.data);
...@@ -74,6 +74,8 @@ class Monitor { ...@@ -74,6 +74,8 @@ class Monitor {
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout(() => { timer = setTimeout(() => {
console.log('hashchange reset'); console.log('hashchange reset');
// 路由跳转的前关闭录制
this.stop();
this.reset({ path: location.hash }); this.reset({ path: location.hash });
}, 1000); }, 1000);
}); });
......
...@@ -13,10 +13,9 @@ class Reporter { ...@@ -13,10 +13,9 @@ class Reporter {
}; };
recordKey = ""; recordKey = "";
environmentUrl = ""; // 环境配置 environmentUrl = ""; // 环境配置
isUploading = false; // 是否在上传cdn
bus = []; // 上传分片数据 bus = []; // 上传分片数据
counter = new Counter(); // 计数器和recordKey一起重置 counter = new Counter(); // 计数器和recordKey一起重置
cache = []; // cdn数据缓存 uploadingPile = new Set([]);
init({ env, ...baseInfo }) { init({ env, ...baseInfo }) {
this.baseInfo = baseInfo; this.baseInfo = baseInfo;
this.setEnvironment(env); this.setEnvironment(env);
...@@ -40,11 +39,21 @@ class Reporter { ...@@ -40,11 +39,21 @@ class Reporter {
} }
// 上传CDN // 上传CDN
toCDN(payload) { toCDN(payload) {
this.isUploading = true;
const blob = new Blob([JSON.stringify(payload)], { type: "application/json" }); const blob = new Blob([JSON.stringify(payload)], { type: "application/json" });
const formData = new FormData(); const formData = new FormData();
// 保存上下文
const trackId = this.counter.count; const trackId = this.counter.count;
const recordKey = this.recordKey;
log('trackId', trackId);
log('recordKey', recordKey);
this.uploadingPile.add(trackId);
formData.append("file", blob, `${this.recordKey + trackId}.json`); formData.append("file", blob, `${this.recordKey + trackId}.json`);
const extra = {
...this.baseInfo,
recordKey: this.recordKey,
trackId: trackId,
isCDN: true
};
try { try {
fetch(`${this.environmentUrl}/upload`, { fetch(`${this.environmentUrl}/upload`, {
// fetch(`http://localhost:3000/upload`, { // fetch(`http://localhost:3000/upload`, {
...@@ -56,36 +65,28 @@ class Reporter { ...@@ -56,36 +65,28 @@ class Reporter {
return res.json(); return res.json();
}) })
.then(res => { .then(res => {
// 如果cache中有数据,说明是多次提交并且数据缓存在了cache中,那么我们全量快照可能在cache[0] /** 因为在路由跳转前可能存在上个路由里面遗留的部分数据,
const snapArr = this.cache && this.cache.length > 0 ? this.cache : this.bus; * 并且销毁dom的时候数据量又大于40000,那么一定调用了上传toCDN的接口
const snapIndex = snapArr.findIndex((item, index) => { * 而toCDN的接口会保存之前的trackId,而this.bus在路由跳转的时候会被清空
if (item.track.type === 2) { * 那么上下文的trackId在this.bus中就会找不到,找到也不是正确的*/
return index; if (this.recordKey !== recordKey) {
} log('路由跳转遗留数据');
}); return;
const extra = {
...this.baseInfo,
recordKey: this.recordKey,
trackId: trackId,
isCDN: true,
};
log("type=2定位", snapIndex);
log("cnd Url", res.data.url);
// 向cache或者bus中注入
if (this.cache && this.cache.length > 0) {
this.cache[0].splice(snapIndex, 1, dataWrapper(extra, res.data.url));
} else { } else {
this.bus.splice(snapIndex, 1, dataWrapper(extra, res.data.url)); const snapIndex = this.bus && this.bus.findIndex((item, index) => {
} if (item.trackId === trackId) {
this.isUploading = false; return index;
// 如果cache里面有数据需要上传的,那么先上传 }
if (this.cache && this.cache.length > 0) {
this.cache.map(item => {
this.report(item);
}); });
this.cache = []; log('snapIndex', snapIndex);
// 向bus中注入
this.bus.splice(snapIndex, 1, dataWrapper(extra, res.data.url));
// 在trackId之前 包括trackId本身的数据全部上传
this.uploadingPile.delete(trackId);
const reportData = this.bus.splice(0, snapIndex + 1);
this.report(reportData);
return res;
} }
return res;
}); });
} catch (e) { } catch (e) {
log("上传失败,原因:", e.message); log("上传失败,原因:", e.message);
...@@ -96,20 +97,26 @@ class Reporter { ...@@ -96,20 +97,26 @@ class Reporter {
...this.baseInfo, ...this.baseInfo,
recordKey: this.recordKey, recordKey: this.recordKey,
trackId: this.counter.next(), trackId: this.counter.next(),
isCDN: false, isCDN: false
}; };
this.bus.push(dataWrapper(extra, data)); this.bus.push(dataWrapper(extra, data));
} }
// 上传 // 尝试上传
report(data) { tryReport(isOverHundred) {
log("上传数据", data); // 如果有cdn的内容在上传,那么我们不做任何的上传直接返回
const reportData = data; if (this.uploadingPile.length > 0) {
this.bus = []; log('有cdn的内容在上传', this.uploadingPile);
if (this.isUploading) {
log("cdn数据正在上传,先将内容存到cache", this.cache);
this.cache.push(reportData);
return; return;
} else {
let reportData = isOverHundred ? this.bus.splice(0, 100) : this.bus.splice(0, this.bus.length);
this.report(reportData);
} }
}
// 真正上传
report(data) {
log("上传数据", data);
log('上传后的bus', this.bus);
try { try {
fetch(`${this.environmentUrl}/behavior/record`, { fetch(`${this.environmentUrl}/behavior/record`, {
// fetch(`http://localhost:3000/behavior/record`, { // fetch(`http://localhost:3000/behavior/record`, {
...@@ -137,14 +144,8 @@ class Reporter { ...@@ -137,14 +144,8 @@ class Reporter {
} }
// 重置数据(分条使用) // 重置数据(分条使用)
reset() { reset() {
// 将前部分的数据在清空前上传
// if(this.bus.length > 0) {
// this.report();
// }
this.cache = [];
this.bus = []; this.bus = [];
this.counter.reset(); this.counter.reset();
this.generateKey();
} }
} }
......
...@@ -14,26 +14,26 @@ onmessage = ({ data: { type, payload } }) => { ...@@ -14,26 +14,26 @@ onmessage = ({ data: { type, payload } }) => {
// todo : 数据本地存储 // todo : 数据本地存储
reporter.toBus(payload); reporter.toBus(payload);
log("bus", reporter.bus); log("bus", reporter.bus);
// todo : 全量快照上传cdn // todo : 全量快照上传cdn || 或者字符内容超过3000
log("track type", payload.type, payload); let strData = JSON.stringify(payload.data);
if (payload.type === 2) { if (payload.type === 2 || strData.length > 40000) {
reporter.toCDN(payload); reporter.toCDN(payload);
} }
// todo : 数据压缩 // todo : 数据压缩
// todo : 根据事件类型优先级触发上传策略(click) // todo : 根据事件类型优先级触发上传策略(click)
if (payload.data.source === 2 && (payload.data.type === 2 || payload.data.type === 3) && !reporter.isUploading) { if (payload.data.source === 2 && (payload.data.type === 2 || payload.data.type === 3)) {
reporter.report(reporter.bus); reporter.tryReport(false);
} }
// todo : 数据超出100条上线,自动上传 // todo : 数据超出100条上线,自动上传
if (reporter.bus.length > 100 && !reporter.isUploading) { if (reporter.bus.length > 100) {
reporter.report(reporter.bus); reporter.tryReport(true);
} }
break; break;
case "reset": case "reset":
// todo : 重置参数,重新生成recordKey // todo : 重置参数,重新生成recordKey
reporter.updateData(payload);
reporter.reset(); reporter.reset();
postMessage('resetRecord'); reporter.updateData(payload);
postMessage('resetRecord'); // 数据重置之后通知录制开启
log("path", reporter.baseInfo.path); log("path", reporter.baseInfo.path);
log("分片id", reporter.recordKey); log("分片id", reporter.recordKey);
break; break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment