preface
Recently miscellaneous miscellaneous things more, rare time to make up for the previous series, owe everyone buried point series now started to go
Why do we need a burial system
In the movie
Very proud of the separation of business and UI development, a variety of design patterns, algorithm optimization in turn, the code to write Perfect (labor code world No.1), No BUG, Perfect program, compatibility No.1, code can play can resist high quality. Punch in after work easily, go home to see baby.
In the real world
In fact, the development environment is not the same as the production environment, and even after the testing process is perfected, there will still be some missed tests. Considering the use of the client environment, network environment and a series of uncertain factors exist.
So there are three principles to keep in mind during development.
- There is no perfect code, only undiscovered bugs
- Never trust a test environment. No test environment covers all online situations
- If there’s no feedback online, don’t be suspicious. The problem should be deep, deep
What is a buried point system
Burial sites are like cameras in cities. From the perspective of products, they can monitor users’ behavior tracks in our products, providing basis for product iteration and project stability. WHO, WHEN, WHERE, HOW and WHAT are the basic dimensions of data collected at burial sites.
For front-end development, it can monitor page resource loading performance and exceptions, provide page experience and health index, provide basis for subsequent performance optimization, and report exceptions and occurrence scenarios in time. So as to be able to timely fix problems, improve the quality of the project, etc.
Burial sites can be roughly divided into three categories:
- Non-trace buried point – collect all information on the page including page in and out, event click and so on, need to carry out data flushing to get useful information
- Visual buried point – According to the generated page structure to obtain a specific point, separate buried point analysis
- Business code manual burial point – According to the specific complex business, remove the above two can not cover the place of business code burial point
Code buried point | Visual burial point | Non-trace buried point | |
---|---|---|---|
A typical scenario | Non-trace buries cannot be covered, such as business data | Simple canonical page scenario | Simple canonical page scenarios, |
advantage | Clear business data | The development cost is low, and the operation personnel can directly carry out the relevant burial site configuration | No configuration is required and data is traceable |
insufficient | Data is not traceable and development costs are high | Business data cannot be associated, and data cannot be traceable | The amount of data is large and cannot be associated with service data |
In most cases, we can collect all the information and data through the non-trace burial point, and then cooperate with the visual burial point to locate a specific point, so that most of the burial point information can be analyzed accordingly.
In special cases, you can add more business code to manually bury points to deal with special scenarios (most of the cases are strong business and normal click, refresh the event has nothing to do with the information to be reported)
Bury some SDK development
Data collection and analysis of burial sites
- Event Basic data
- Event time
- Snapshot of page information when it occurs
- page
- Page PV, UV
- User page duration
- Page Jump Event
- The page goes to background
- The user leaves the page
- The user information
- User’s uid
- User device fingerprint
- Equipment information
- ip
- positioning
- User action
- The user clicks
- Click on the target
- The user clicks
- Page AJAX request
- The request is successful
- The request failed
- The request timeout
- An error page
- An error occurred during resource loading
- JS runtime error
- Resource loading new performance
- The picture
- The script
- Page loading performance
The above data defines buried point events in three dimensions
- ,
LEVEL
: Describes the log level of buried dataINFO
Some user operations, request success, resource loading, etcERROR
: JS error, interface error and so on error type data recordDEBUG
: Reserved for developers to manually call back data records that exclude bugsWARN
: Reserved for developers to manually call back data records of abnormal user behavior
CATEGORY
: Describes the classification of buried point dataTRACK
: The lifecycle of the buried point SDK object manages the entire buried point data.WILL_MOUNT
: The SDK object is about to be initialized to load, generate a default ID, and track all related eventsDID_MOUNTED
: The SDK object initialization is completed, and asynchronous operations such as obtaining device fingerprint are completed
AJAX
: AJAX dataERROR
: Abnormal data on the pagePERFORMANCE
: About performance dataOPERATION
: Users operate related data
EVENT_NAME
: Specifies the event name
Based on the above dimensions, we can simply design the following architecture
Based on the architecture above, proceed with the following specific code development
The agent requests
There are now two main ways to request in the browser, XMLHttpRequest and Fetch.
Agent XMLHttpRequest
function NewXHR() {
var realXHR: any = new OldXHR(); // The proxy mode is mentioned
realXHR.id = guid()
const oldSend = realXHR.send;
realXHR.send = function (body) {
oldSend.call(this, body)
// Record the burial point
}
realXHR.addEventListener('load'.function () {
// Record the burial point
}, false);
realXHR.addEventListener('abort'.function () {
// Record the burial point
}, false);
realXHR.addEventListener('error'.function () {
// Record the burial point
}, false);
realXHR.addEventListener('timeout'.function () {
// Record the burial point
}, false);
return realXHR;
}
Copy the code
The agent the Fetch
const oldFetch = window.fetch;
function newFetch(url, init) {
const fetchObj = {
url: url,
method: method,
body: body,
}
ajaxEventTrigger.call(fetchObj, AJAX_START);
return oldFetch.apply(this.arguments).then(function (response) {
if (response.ok) {
// Record the burial point
} else {
// Report an error
}
return response
}).catch(function (error) {
fetchObj.error = error
// Record the burial point
throw error
})
}
Copy the code
Page-listeningPV
.UV
When entering the page, we generated a unique session ID through the algorithm, which was used as the global ID of the buried point behavior, and reported the user ID, device fingerprint and device information. When the user is not logged in, the device fingerprint is used to calculate UV and the session ID is used to calculate PV.
Exception handling
An exception is an unusual incident that interferes with the normal flow of a program
RUNTIME ERROR
Runtime exceptions can be caught in JS via window.onError and window.addeventListener (‘error’, callback). Window.onerror is more compatible.
window.onerror = function(message, url, lineno, columnNo, error) {
const lowCashMessage = message.toLowerCase()
if(lowCashMessage.indexOf('script error') > -1) {
return
}
const detail = {
url: url
filename: filename,
columnNo: columnNo,
lineno: lineno,
stack: error.stack,
message: message
}
// Record the burial point
}
Copy the code
Script Error
Here we filter Script Error, which is mainly caused by the Error of the third-party cross-domain Script loaded in the page, such as THE JS Script hosted in the third-party CDN. This kind of problem is difficult to identify. The solutions are:
- Open the
CORS
(Cross Origin Resource Sharing), perform the following steps<srcipt src="another domain/main.js" cossorigin="anonymous"></script>
- Modify the
Access - Control - Allow - Origin: * | specify the domain name
- use
try catch
<script scr="crgt.js"></script> // Load the CRGT script, window.crgt = {getUser: () => string} try{window.crgt.getUser(); }catch(error) { throw error // output the correct error stack}Copy the code
Promise reject
An unhandledrejection error is thrown when a Promise object is rejected and not processed. This error is not caught by any of the above methods, so separate processing events need to be added.
window.addEventListener("unhandledrejection".event= > {
throw event.reason
});
Copy the code
Abnormal resource loading
In the browser, window.addeventListener (‘error’, callback) can be used to listen for resource loading exceptions, such as missing JS or CSS script files.
window.addEventListener('error'.(event) = > {
if (event.target instanceof HTMLElement) {
const target = parseDom(event.target, ['src']);
const detail = {
target: target,
path: parseXPath(target),
}
// Record the burial point}},true)
Copy the code
Listening to user behavior
Listen for the click event via addEventListener Click
window.addEventListener('click'.(event) = > {
// Record the burial point
}, true)
Copy the code
The element is located here by the component’s displaName, which represents the component’s file directory, For example, the component FormItem exported from the SRC /components/ form.js file is automatically added to the property @components/ form.formItem by the Babel Plugin. Or the consumer actively adds the static displayName property to the component.
Page Route change
- hashRouter
Listen for hash changes on the page and parse the hash
window.addEventListener('hashchange'.event= > {
const { oldURL, newURL } = event;
const oldURLObj = url.parseUrl(oldURL);
const newURLObj = url.parseUrl(newURL);
const from = oldURLObj.hash && url.parseHash(oldURLObj.hash);
const to = newURLObj.hash && url.parseHash(newURLObj.hash);
if(!from && !to ) return;
// Record the burial point
})
Copy the code
Listen to the page leave
Listen for off-page events via addEventListener beforeUnload
window.addEventListener('beforeunload'.(event) = > {
// Record the burial point
})
Copy the code
The SDK framework
class Observable {
constructor(observer) {
observer(this.emit)
}
emit = (data) = > {
this.listeners.forEach(listener= > {
listener(data)
})
}
listeners = [];
subscribe = (listener) = > {
this.listeners.push(listeners);
return () = > {
const index = this.listeners.indexOf(listener);
if(index === -1) {
return false
}
this.listeners.splice(index, 1);
return true; }}}Copy the code
const clickObservable = new Observable((emit) = > {
window.addEventListener('click', emit)
})
Copy the code
However, when dealing with Ajax, which requires multiple data combinations and merg operations, it is less elegant and difficult to adapt to subsequent complex data flow operations.
const ajaxErrorObservable = new Observable((emit) = > {
window.addEventListener(AJAX_ERROR, emit)
})
const ajaxSuccessObservable = new Observable((emit) = > {
window.addEventListener(AJAX_SUCCESS, emit)
})
const ajaxTimeoutObservable = new Observable((emit) = > {
window.addEventListener(AJAX_TIMEOUT, emit)
})
Copy the code
You can choose RxJS to optimize your code
export const ajaxError$ = fromEvent(window.'AJAX_ERROR'.true)
export const ajaxSuccess$ = fromEvent(window.'AJAX_SUCCESS'.true)
export const ajaxTimeout$ = fromEvent(window.'AJAX_TIMEOUT'.true)
Copy the code
ajaxError$.pipe(
merge(ajaxSuccess$, ajaxTimeout$),
map(data= > (data) = > ({category: 'ajax', data; data}))
subscribe(data= > console.log(data))
Copy the code
The map and merge operators are used to merge and process data.
The data flow
The project structure
core
event$
Data stream mergesnapshot
Get the current device snapshot, for exampleurl
.userID
.router
track
Buried point classes, combining data flows and logs.
logger
logger
The log classinfo
warn
debug
error
observable
ajax
beforeUpload
opeartion
routerChange
logger
track
reference
- www.alibabacloud.com/help/zh/doc…
At the end
Self-built buried-point systems are a collaborative effort between the front and back ends. If manpower is scarce, it is recommended to use third-party analytics plug-ins, such as Sentry, which are sufficient for most daily use
However, it is recommended to understand more, in the third party plug-in can not meet the business needs of the time, you can top.
Project Actual Combat Series
| cache handling project practical experience
Project practice | basic request encapsulation
Implement project of actual combat | business processing layer