html:前端如何高性能渲染十万条数据?有什么方法?
answer:
对于一次性插入大量数据的情况,一般有两种做法:
- 时间分片
- 虚拟列表
最粗暴的做法,一次性将大量数据插入到页面中:
<ul id="container"></ul>
// 记录任务开始时间
let now = Date.now();
// 插入十万条数据
const total = 100000;
// 获取容器
let ul = document.getElementById('container');
// 将数据插入容器中
for (let i = 0; i < total; i++) {
let li = document.createElement('li');
li.innerText = ~~(Math.random() * total)
ul.appendChild(li);
}
console.log('JS运行时间:',Date.now() - now);
setTimeout(()=>{
console.log('总运行时间:',Date.now() - now);
},0)
// print: JS运行时间: 187
// print: 总运行时间: 2844
两次console.log的结果时间差异巨大,为什么呢?
因为在 JS 的Event Loop中,当JS引擎所管理的执行栈中的事件和所有微任务事件全部执行完后,才会触发渲染线程对页面进行渲染,所以:
第一个console.log的触发时间是在页面进行渲染之前,此时得到的间隔时间为JS运行所需要的时间
第二个console.log是放到 setTimeout 中的,它的触发时间是在渲染完成,在下一次Event Loop中执行的。
对于大量数据渲染的时候,JS运算并不是性能的瓶颈,性能的瓶颈主要在于渲染阶段。
从上面的例子,我们已经知道,页面的卡顿是由于同时渲染大量DOM所引起的,所以我们考虑将渲染过程分批进行
在这里,我们使用setTimeout来实现分批渲染
<ul id="container"></ul>
//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每页多少条
let pageCount = Math.min(curTotal , once);
setTimeout(()=>{
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount,curIndex + pageCount)
},0)
}
loop(total,index);
虽然页面加载的时间已经非常快了,每次刷新时可以很快的看到第一屏的所有数据,但是当我们快速滚动页面的时候,会发现页面出现闪屏或白屏的现象。(人的眼睛有视觉停留效应,即前一副画面留在大脑的印象还没消失,紧接着后一副画面就跟上来了, 这中间只间隔了16.7ms(1000/60≈16.7),大多数电脑显示器的刷新频率是60Hz,大概相当于每秒钟重绘60次,FPS为60frame/s,为这个值的设定受屏幕分辨率、屏幕尺寸和显卡的影响。所以会让你误以为屏幕上的图像是静止不动的)。
原因:setTimeout的执行时间并不是确定的。在JS中,setTimeout任务被放进事件队列中,只有主线程执行完才会去检查事件队列中的任务是否需要执行,因此setTimeout的实际执行时间可能会比其设定的时间晚一些。
刷新频率受屏幕分辨率和屏幕尺寸的影响,因此不同设备的刷新频率可能会不同,而setTimeout只能设置一个固定时间间隔,这个时间不一定和屏幕的刷新时间相同。
requestAnimationFrame完成渲染:最大的优势是由系统来决定回调函数的执行时机。
如果屏幕刷新率是60Hz,那么回调函数就每16.7ms被执行一次,如果刷新率是75Hz,那么这个时间间隔就变成了1000/75=13.3ms,换句话说就是,requestAnimationFrame的步伐跟着系统的刷新步伐走。它能保证回调函数在屏幕每一次的刷新间隔中只被执行一次,这样就不会引起丢帧现象。
我们使用requestAnimationFrame来进行分批渲染:
<ul id="container"></ul>
//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每页多少条
let pageCount = Math.min(curTotal , once);
window.requestAnimationFrame(function(){
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
ul.appendChild(li)
}
loop(curTotal - pageCount,curIndex + pageCount)
})
}
loop(total,index);
还可以使用 DocumentFragment
DocumentFragment,文档片段接口,表示一个没有父级文件的最小文档对象。
它被作为一个轻量版的Document使用,
用于存储已排好版的或尚未打理好格式的XML片段。
最大的区别是因为DocumentFragment不是真实DOM树的一部分,
它的变化不会触发DOM树的(重新渲染) ,且不会导致性能等问题。
可以使用document.createDocumentFragment方法
或者构造函数来创建一个空的DocumentFragment
<ul id="container"></ul>
//需要插入的容器
let ul = document.getElementById('container');
// 插入十万条数据
let total = 100000;
// 一次插入 20 条
let once = 20;
//总页数
let page = total/once
//每条记录的索引
let index = 0;
//循环加载数据
function loop(curTotal,curIndex){
if(curTotal <= 0){
return false;
}
//每页多少条
let pageCount = Math.min(curTotal , once);
window.requestAnimationFrame(function(){
let fragment = document.createDocumentFragment();
for(let i = 0; i < pageCount; i++){
let li = document.createElement('li');
li.innerText = curIndex + i + ' : ' + ~~(Math.random() * total)
fragment.appendChild(li)
}
ul.appendChild(fragment)
loop(curTotal - pageCount,curIndex + pageCount)
})
}
loop(total,index);
nodejs:知道eggjs和thinkjs吗,有什么区别?
ThinkJS / Sails / LoopBack 等属于上层框架;
Egg 是微内核 + 插件模式,为上层框架服务;
html:怎么样写出优雅的html结构?
1.不同类型文件进行文件夹分类,css js img 等等
2.避免重复代码,js代码和css 代码分别写到单独文件中,然后再htm中引入,注意引入的先后顺序。就是结构层、表现层、行为层拆分。
3.代码结构接近视觉顺序,块级元素另起一行。
软技能:git pull报错怎么办
git pull 命令等同于先做了git fetch ,再做了git merge, 当git merge后有可能会报错:Your local changes would be overwritten by merge. Commit, stash or revert them to proceed
报错原因是你对本地的代码进行了更改,而未对代码进行提交、存放或还原
解决方法:使用git stash先将更改的代码暂存起来。
git stash命令可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。
使用git stash将未提交的代码保存之后,现在仓库的状态是和上一次提交的内容是完全一样的
此时再进行git merge temp就不会报错了。
git stash 工作树模型:H是HEAD提交.I是存储单元的提交.W是工作树中的提交.
git stash常用命令:
1 git stash等同于git stash save存储的修改列表.
2 git stash list查看.
3 git stash show用于校验,
4 git stash apply用于重新存储.
html:如何适应异形屏?
margin :0 auto;
width:1000px;
麻烦的就看这个:沉浸式异形屏解决
css3:动态信封折叠效果
css:body, div, h1, h2, form, fieldset, input, textarea, footer, p { margin: 0; padding: 0; border: 0; outline: none; } @font-face { font-family: 'YanoneKaffeesatzRegular'; src: url('yanonekaffeesatz-regular-webfont.eot'); src: url('yanonekaffeesatz-regular-webfont.eot?#iefix') format('embedded-opentype'), url('yanonekaffeesatz-regular-webfont.woff') format('woff'), url('yanonekaffeesatz-regular-webfont.ttf') format('truetype'), url('yanonekaffeesatz-regular-webfont.svg#YanoneKaffeesatzRegular') format('svg'); font-weight: normal; font-style: normal; } body { background: #ccc url('../images/bg_out.png'); color: #7c7873; font-family: 'YanoneKaffeesatzRegular'; } p { text-shadow:0 1px 0 #fff; font-size:24px; } #wrap { width:530px; margin:20px auto 0; height:1000px; } h1 { margin-bottom:20px; text-align:center; font-size:48px; text-shadow:0 1px 0 #ede8d9; } #form_wrap { overflow:hidden; height:446px; position:relative; top:0px; -webkit-transition: all 1s ease-in-out .3s; -moz-transition: all 1s ease-in-out .3s; -o-transition: all 1s ease-in-out .3s; transition: all 1s ease-in-out .3s; } #form_wrap:before { content:""; position:absolute; bottom:128px; left:0px; background:url('../images/before.png'); width:530px; height: 316px; } #form_wrap:after { content:""; position:absolute; bottom:0px; left:0; background:url('../images/after.png'); width:530px; height: 260px; } #form_wrap.hide:after, #form_wrap.hide:before { display:none; } #form_wrap:hover { height:776px; top:-200px; } form { background:#f7f2ec url('../images/letter_bg.png'); position:relative; top:200px; overflow:hidden; height:200px; width:400px; margin:0px auto; padding:20px; border: 1px solid #fff; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; box-shadow: 0px 0px 3px #9d9d9d, inset 0px 0px 27px #fff; -moz-box-shadow: 0px 0px 3px #9d9d9d, inset 0px 0px 14px #fff; -webkit-box-shadow: 0px 0px 3px #9d9d9d, inset 0px 0px 27px #fff; -webkit-transition: all 1s ease-in-out .3s; -moz-transition: all 1s ease-in-out .3s; -o-transition: all 1s ease-in-out .3s; transition: all 1s ease-in-out .3s; } #form_wrap:hover form { height:530px; } label { margin: 11px 20px 0 0; font-size: 16px; color: #b3aba1; text-transform: uppercase; text-shadow: 0px 1px 0px #fff; } input[type=text], textarea { font: 14px normal normal uppercase helvetica, arial, serif; color: #7c7873; background:none; width: 380px; height: 36px; padding: 0px 10px; margin: 0 0 10px 0; border:1px solid #f8f5f1; -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; -moz-box-shadow: inset 0px 0px 1px #726959; -webkit-box-shadow: inset 0px 0px 1px #b3a895; box-shadow: inset 0px 0px 1px #b3a895; } textarea { height: 80px; padding-top:14px; } textarea:focus, input[type=text]:focus { background:rgba(255, 255, 255, .35); } #form_wrap input[type=submit] { position:relative; font-family: 'YanoneKaffeesatzRegular'; font-size:24px; color: #7c7873; text-shadow:0 1px 0 #fff; width:100%; text-align:center; opacity:0; background:none; cursor: pointer; -moz-border-radius: 3px; -webkit-border-radius: 3px; border-radius: 3px; -webkit-transition: opacity .6s ease-in-out 0s; -moz-transition: opacity .6s ease-in-out 0s; -o-transition: opacity .6s ease-in-out 0s; transition: opacity .6s ease-in-out 0s; } #form_wrap:hover input[type=submit] { z-index:1; opacity:1; -webkit-transition: opacity .5s ease-in-out 1.3s; -moz-transition: opacity .5s ease-in-out 1.3s; -o-transition: opacity .5s ease-in-out 1.3s; transition: opacity .5s ease-in-out 1.3s; } #form_wrap:hover input:hover[type=submit] { color:#435c70; }
html:
`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CSS3实现动态信封折叠留言样式</title>
<script src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>
<!--[if IE]><script>
$(document).ready(function() {
$("#form_wrap").addClass('hide');
})
</script><![endif]-->
<link href="css/lanrenzhijia.css" type="text/css" rel="stylesheet" />
</head>
<body>
<div id="wrap">
<h1>Send a message</h1>
<div id='form_wrap'>
<form>
<p>Hello Joe,</p>
<label for="email">Your Message : </label>
<textarea name="message" value="Your Message" id="message" ></textarea>
<p>Best,</p>
<label for="name">Name: </label>
<input type="text" name="name" value="" id="name" />
<label for="email">Email: </label>
<input type="text" name="email" value="" id="email" />
<input type="submit" name ="submit" value="Now, I send, thanks!" />
</form>
</div>
</div>
</body>
</html>
(已经校招去赛意了,武汉公司,希望有一个好结果吧!)