写点什么

自建开发工具系列 -Webkit 内存动量监控 UI(四)

用户头像
Tim
关注
发布于: 3 小时前
自建开发工具系列-Webkit内存动量监控UI(四)

本期将 UI 部分分为计算核心部分和输出 UI 的部分, 分类规划逻辑与实践


计算核心部分使用的纯函数,状态其实没有存储,而是使用 DOM 的数据进行状态增补。


  const nodeUI = document.createElement('div');  nodeUI.id = 'nodeUI';  nodeUI.style.cssText = `position:relative;width:120px;height:${TOOLS_HEIGHT}px;background-color:lightyellow`;  panel.appendChild(nodeUI);
// 刷新后增加新的内存值和GC状态 while (nodeUI.children.length < 120) { const bar = document.createElement('span'); bar.style.cssText = `width:1px;height:${TOOLS_HEIGHT}px;float:left;background-color:black`; nodeUI.appendChild(bar); }
复制代码


现在先制定一个 panel,然后将内存记录按照柱状条更新在 panel 中,结合 GC,需要合并两种信息。


  const updateData = function (dom, height, color) {    const child = dom.appendChild(dom.firstChild);    child.style.height = `${height}px`;    if (color) child.style.backgroundColor = color;  };
const refreshGraph = function (dom, oHFactor, hFactor) { [].forEach.call(dom.children, (c) => { const cHeight = c.style.height.substring(0, c.style.height.length - 2);
// 转换到 MB const newVal = TOOLS_HEIGHT - ((TOOLS_HEIGHT - cHeight) / oHFactor) * hFactor; c.style.height = `${newVal}px`; }); };
复制代码


然后再输出刷新函数


  return {    domElement: toolsDom,    update() {      // 每秒刷新      if (Date.now() - lastTime < 1000 / 1) return;      lastTime = Date.now();
delta = performance.memory.usedJSHeapSize - lastUsedHeap; lastUsedHeap = performance.memory.usedJSHeapSize;
// GC 判定,如果是清空内存,则使用绿色标识 color = delta < 0 ? 'green' : 'black';
ms = lastUsedHeap; memoryBottom = Math.min(memoryBottom, ms); memoryTop = Math.max(memoryTop, ms); noticeLabel.textContent = window.performance.memory.jsHeapSizeLimit ? `内存使用: ${bytesToMB(ms)}` : 'Only Webkit';
mbValue = ms / (1024 * 1024);
if (mbValue > MemoryLimitValue) { factor = (mbValue - (mbValue % TOOLS_HEIGHT)) / TOOLS_HEIGHT; newThreshold = TOOLS_HEIGHT * (factor + 1); refreshGraph(nodeUI, TOOLS_HEIGHT / MemoryLimitValue, TOOLS_HEIGHT / newThreshold); MemoryLimitValue = newThreshold; }
updateData(nodeUI, TOOLS_HEIGHT - mbValue * (TOOLS_HEIGHT / MemoryLimitValue), color); } };
复制代码


完成体的代码为,放在目录的 utils.js 里


const displayPanel = function () {  let memoryBottom = 100;  let memoryTop = 0;  const TOOLS_HEIGHT = 30;  let MemoryLimitValue = TOOLS_HEIGHT;
const toolsDom = document.createElement('div'); toolsDom.id = 'twm'; toolsDom.className = 'tools'; toolsDom.style.cssText = 'width:130;height:48px;opacity:0.9;cursor:pointer;overflow:hidden;z-index:10000;will-change:transform;';
const panel = document.createElement('div'); panel.id = 'ms'; panel.style.cssText = 'padding:0 0 3px 3px;text-align:left;background-color:black;'; toolsDom.appendChild(panel);
const noticeLabel = document.createElement('div'); noticeLabel.id = 'noticeLabel'; noticeLabel.style.cssText = 'color:white;font-family:Arial;font-size:9px;font-weight:bold;line-height:15px'; noticeLabel.innerHTML = ''; panel.appendChild(noticeLabel);
const nodeUI = document.createElement('div'); nodeUI.id = 'nodeUI'; nodeUI.style.cssText = `position:relative;width:120px;height:${TOOLS_HEIGHT}px;background-color:lightyellow`; panel.appendChild(nodeUI);
// 刷新后增加新的内存值和GC状态 while (nodeUI.children.length < 120) { const bar = document.createElement('span'); bar.style.cssText = `width:1px;height:${TOOLS_HEIGHT}px;float:left;background-color:black`; nodeUI.appendChild(bar); }
const updateData = function (dom, height, color) { const child = dom.appendChild(dom.firstChild); child.style.height = `${height}px`; if (color) child.style.backgroundColor = color; };
const refreshGraph = function (dom, oHFactor, hFactor) { [].forEach.call(dom.children, (c) => { const cHeight = c.style.height.substring(0, c.style.height.length - 2);
// 转换到 MB const newVal = TOOLS_HEIGHT - ((TOOLS_HEIGHT - cHeight) / oHFactor) * hFactor;
c.style.height = `${newVal}px`; }); };
// 避免没有 window.performance.memory 的浏览器崩溃 if (window.performance && !performance.memory) { performance.memory = { usedJSHeapSize: 0, totalJSHeapSize: 0 }; }
let precision; let i;
function bytesToMB(bytes) { precision = Math.pow(10, 0); i = Math.floor(Math.log(bytes) / Math.log(1024)); return `${Math.round((bytes * precision) / Math.pow(1024, i)) / precision} MB`; }
let lastTime = Date.now(); let lastUsedHeap = performance.memory.usedJSHeapSize; let delta = 0; let color = 'black'; let ms = 0; let mbValue = 0; let factor = 0; let newThreshold = 0;
return { domElement: toolsDom, update() { // 每秒刷新 if (Date.now() - lastTime < 1000 / 1) return; lastTime = Date.now();
delta = performance.memory.usedJSHeapSize - lastUsedHeap; lastUsedHeap = performance.memory.usedJSHeapSize;
// GC 判定,如果是清空内存,则使用绿色标识 color = delta < 0 ? 'green' : 'black';
ms = lastUsedHeap; memoryBottom = Math.min(memoryBottom, ms); memoryTop = Math.max(memoryTop, ms); noticeLabel.textContent = window.performance.memory.jsHeapSizeLimit ? `内存使用: ${bytesToMB(ms)}` : 'Only Webkit';
mbValue = ms / (1024 * 1024);
if (mbValue > MemoryLimitValue) { factor = (mbValue - (mbValue % TOOLS_HEIGHT)) / TOOLS_HEIGHT; newThreshold = TOOLS_HEIGHT * (factor + 1); refreshGraph(nodeUI, TOOLS_HEIGHT / MemoryLimitValue, TOOLS_HEIGHT / newThreshold); MemoryLimitValue = newThreshold; }
updateData(nodeUI, TOOLS_HEIGHT - mbValue * (TOOLS_HEIGHT / MemoryLimitValue), color); }
};};
export default displayPanel;
复制代码


制作 UI 需要将组件以一种简单的方式输出,以便加载时简单引用,这部分用 react 来封装


import * as React from 'react';import './App.css';import displayPanel from './utils';

class App extends React.Component { constructor(props) { super(props); this.state = { twm: displayPanel() }; }
componentDidMount() { const updateLoop = () => { if (this.refs.toolsNode.appendChild) { this.refs.toolsNode.appendChild(this.state.twm.domElement); } if (this.state.twm) { this.state.twm.update(); } if (window.performance.memory.jsHeapSizeLimit) { window.setTimeout(updateLoop, 1000) } } window.setTimeout(updateLoop, 1000) }
render() { return <div style={{top: '0px', right: '0px', position: 'fixed'}} ref="toolsNode" className="displayPanel" />; }}
export default App;
复制代码


然后咱们来看一下在 Create React App 生成的项目中简单的引用


import React from 'react';import ReactDOM from 'react-dom';import './index.css';import App from './App';import reportWebVitals from './reportWebVitals';
ReactDOM.render( <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root'));
复制代码



下期继续更新完善这个工具

发布于: 3 小时前阅读数: 2
用户头像

Tim

关注

还未添加个人签名 2018.05.01 加入

还未添加个人简介

评论

发布
暂无评论
自建开发工具系列-Webkit内存动量监控UI(四)