/*!
* jLayout JQuery Plugin v0.17
*
* Licensed under the new BSD License.
* Copyright 2008-2009 Bram Stein
* All rights reserved.
*/
/*global jQuery jLayout*/
if (jQuery &&jLayout) {
(function ($) {
/**
* This wraps jQuery objects in another object that supplies
* the methods required for the layout algorithms.
*/
function wrap(item, resize) {
var that = {}
$.each(['min', 'max'], function (i, name) {
that[name + 'imumSize'] = function (value) {
var l = item.data('jlayout')
if (l) {
return l[name + 'imum'](that)
} else {
return item[name + 'Size'](value)
}
}
})
$.extend(that, {
doLayout: function () {
var l = item.data('jlayout')
if (l) {
l.layout(that)
}
item.css({position: 'absolute'})
},
isVisible: function () {
return item.isVisible()
},
insets: function () {
var p = item.padding(),
b = item.border()
return {
'top': p.top,
'bottom': p.bottom + b.bottom + b.top,
'left': p.left,
'right': p.right + b.right + b.left
}
},
bounds: function (value) {
var tmp = {}
if (value) {
if (typeof value.x === 'number') {
tmp.left = value.x
}
if (typeof value.y === 'number') {
tmp.top = value.y
}
if (typeof value.width === 'number') {
tmp.width = (value.width - (item.outerWidth(true) - item.width()))
tmp.width = (tmp.width >= 0) ? tmp.width : 0
}
if (typeof value.height === 'number') {
tmp.height = value.height - (item.outerHeight(true) - item.height())
tmp.height = (tmp.height >= 0) ? tmp.height : 0
}
item.css(tmp)
return item
} else {
tmp = item.position()
return {
'x': tmp.left,
'y': tmp.top,
'width': item.outerWidth(false),
'height': item.outerHeight(false)
}
}
},
preferredSize: function () {
var minSize,
maxSize,
margin = item.margin(),
size = {width: 0, height: 0},
l = item.data('jlayout')
if (l &&resize) {
size = l.preferred(that)
minSize = that.minimumSize()
maxSize = that.maximumSize()
size.width += margin.left + margin.right
size.height += margin.top + margin.bottom
if (size.width <minSize.width || size.height <minSize.height) {
size.width = Math.max(size.width, minSize.width)
size.height = Math.max(size.height, minSize.height)
} else if (size.width >maxSize.width || size.height >maxSize.height) {
size.width = Math.min(size.width, maxSize.width)
size.height = Math.min(size.height, maxSize.height)
}
} else {
size = that.bounds()
size.width += margin.left + margin.right
size.height += margin.top + margin.bottom
}
return size
}
})
return that
}
$.fn.layout = function (options) {
var opts = $.extend({}, $.fn.layout.defaults, options)
return $.each(this, function () {
var element = $(this),
o = $.metadata &&element.metadata().layout ? $.extend(opts, element.metadata().layout) : opts,
elementWrapper = wrap(element, o.resize)
if (o.type === 'border' &&typeof jLayout.border !== 'undefined') {
$.each(['north', 'south', 'west', 'east', 'center'], function (i, name) {
if (element.children().hasClass(name)) {
o[name] = wrap(element.children('.' + name + ':first'))
}
})
element.data('jlayout', jLayout.border(o))
} else if (o.type === 'grid' &&typeof jLayout.grid !== 'undefined') {
o.items = []
element.children().each(function (i) {
if (!$(this).hasClass('ui-resizable-handle')) {
o.items[i] = wrap($(this))
}
})
element.data('jlayout', jLayout.grid(o))
} else if (o.type === 'flexGrid' &&typeof jLayout.flexGrid !== 'undefined') {
o.items = []
element.children().each(function (i) {
if (!$(this).hasClass('ui-resizable-handle')) {
o.items[i] = wrap($(this))
}
})
element.data('jlayout', jLayout.flexGrid(o))
} else if (o.type === 'column' &&typeof jLayout.column !== 'undefined') {
o.items = []
element.children().each(function (i) {
if (!$(this).hasClass('ui-resizable-handle')) {
o.items[i] = wrap($(this))
}
})
element.data('jlayout', jLayout.column(o))
} else if (o.type === 'flow' &&typeof jLayout.flow !== 'undefined') {
o.items = []
element.children().each(function (i) {
if (!$(this).hasClass('ui-resizable-handle')) {
o.items[i] = wrap($(this))
}
})
element.data('jlayout', jLayout.flow(o))
}
if (o.resize) {
elementWrapper.bounds(elementWrapper.preferredSize())
}
elementWrapper.doLayout()
element.css({position: 'relative'})
if ($.ui !== undefined) {
element.addClass('ui-widget')
}
})
}
$.fn.layout.defaults = {
resize: true,
type: 'grid'
}
})(jQuery)
}
一、首先我们简单了解下浏览器的渲染过程:
1.解析HTML抽象DOM Tree
2.抽象出Render Tree
3.布局(layout)render tree
4.绘画render tree
HTML解析成DOM,抽象DOM Tree
解析html文档并将解析的元素转换为dom树中的实际dom节点。
把CSS解析成CSSOM,抽象CSSOM Tree
当浏览器解析dom的时候,遇到link标签,引用外部的css样式表,引擎会将css抽象成cssom
构建渲染树(Render Tree)
DOM和CSSOM合并就产生了Render Tree。构建渲染树大致步骤:
①从dom树的根开始,遍历每个可见节点。
②对于每个可见节点,浏览器找到适当的匹配cssom规则并应用它们。
③它会发布带有内容和计算样式的可见节点。
④每个渲染器代表一个矩形区域,通常对应于一个节点的CSS框。
渲染树的布局
①当渲染器被创建并添加到树中时,它没有位置和大小。计算这些值称为布局。
②布局是一个递归过程,从根元素开始,也就是html,每个渲染器都会去计算他自己的位置和大小,由于浏览器使用流式布局,对Render Tree的计算通常只需要遍历一次就可以完成,但table及其内部元素除外,他们可能需要多次计算,通常要花3倍于同等元素的时间,这也是为什么要避免使用table布局的原因之一。
绘制渲染树
遍历渲染器树,调用渲染器的paint()方法,然后展示。
二、回流和重绘(reflow和repaint)
1. 理解回流和重绘
回流: 当元素的结构、位置、尺寸或某些属性发生改变时,浏览器需要重新计算样式和渲染树;
重绘:当元素发生的改变只影响了节点的一些样式(背景色,边框颜色,文字颜色等),浏览器只需要将新样式赋予给这个元素并重绘它。
需要注意的是, 回流必将引起重绘,重绘不一定会引起回流。
2.如何触发回流
(1)页面首次渲染
(2)DOM树变化(如:增删可见dom节点)
(3)浏览器窗口resize
(4)元素尺寸或位置发生改变
(5)查询布局信息,包括offsetLeft、offsetTop、offsetWidth、offsetHeight、 scrollTop/Left/Width/Height、clientTop/Left/Width/Height、调用了getComputedStyle()或者IE的currentStyle时,浏览器为了返回最新值,会触发回流。
3. 如何触发重绘
背景色、颜色、字体改变,(例如:color、background-color、visibility等,注意:字体大小发生变化时,会触发回流)
三、可减少回流和重绘,优化渲染性能
1.尽量避免改变和多次读取布局属性。如width, height, left, top。
2.除了transforms 或者 opacity属性都会引起重绘,做动画的时候要注意,尽量使用这两个属性;
3.将复杂的节点元素脱离文档流,降低回流成本。
4.缓存布局信息
5.使元素进行动画效果的时候脱离文档流,可先绝对定位,设置好后再恢复。
部分参考:https://segmentfault.com/a/1190000014474575?from=singlemessage&isappinstalled=0
直接写在同一页面和将js代码写在其他页面再引入到该也执行效果是一样的,同样的代码占用 的内存基本是相差无几,之所以写到另一页是为了方便开发和维护。下面我说一下个人对于js代码占用内存的一些看法:1、JavaScript代码确实要比html和css代码消耗内存多,尤其是DOM操作。
作为一个前端开发人员可能都听到过这样的话:尽量减少DOM操作。但是为什么呢?原因很简单,过多的JavaScript代码和过多的dom操作会网页的加载速度慢,当然也会增加内存的开销。但是问题又来了为什么过多的dom操作会导致增加内存开销和导致浏览器变慢呢? 首先,DOM对象本身也是一个js对象,所以严格来说,并不是操作这个对象慢,而是说操作了这个对象后,会触发一些浏览器行为,比如布局(layout)和绘制(paint)。js的一些操作会打破常规,并触发浏览器执行layout:如通过js获取需要计算的DOM属性、添加或删除DOM元素、通过js修改DOM元素样式且该样式涉及到尺寸的改变等。所以频繁的DOM操作确实是可以增加内存开销影响web的性能。
2、哪些方法可以优化这个问题呢?
显然问题引入外接的JavaScript代码和这直接写入网页内的script标记间的JavaScript代码对于的执行效率是一样的。但是对弈页面中的一些不可避免的dom操作我们应该如何最大限度的优化这个问题呢?
a、良好的编程思想,减少代码冗余,尽量代码复用。
简单的说就是我们需要使用面向对象的编程思想尽量将我们常用的功能进行封装然后复用,这样可以在一定程度上减少一些不必要的DOM操作。
b、适当使用一些优化的方法和。
如原生的JavaScript中有一个有一个方法是文档碎片(DocumentFragment() ),使用该方法可以将多个类似的DOM操作挂在文档碎片中,最后执行相当于一次DOM操作的开销。
最后,作为一个前端开发人员对于web性能我们要关注尤其是JavaScript,这要求我们在开发过程中要有一个好的代码习惯。