前端性能优化:5.高性能的JavaScript代码

用户通过浏览器访问页面的过程,除了输入URL地址到所访问页面完成首屏渲染,更多的时候页面在相应与用户的交互。
高性能网站的要求不仅是执行顺畅无BUG,还希望对用户的页面操作能够更快速响应,而且在执行完任务的同时占用更少的资源。

5.1 数据存取

无论哪种计算机语言,说到底它们的作用都是对数据的存取与处理,JavaScript也不例外。若能在处理数据之前,更快速的读取到数据,那么必然会对程序执行性能产生积极的作用。本节建工数据的存取及作用域链的角度,探讨一些在JavaScript中能提升性能的方式。

5.1.1 数据存取方式
一般来说JavaScript有四种数据存取方式:

  1. 直接字面量:字面量不存储在特定位置也不需要索引,仅代表自身。包括布尔值、数字、字符串、对象、数组、函数、null、undefined及正则表达式。
  2. 变量:通过关键字const/let/var定义的数据存储单元。
  3. 数组元素:存储在数组对象内部,通过数组下标数字进行索引。
  4. 对象属性:存储在对象内部,通过对象的字符串名称进行索引。

数组元素和对象属性不仅可以是直接字面量的形式,还可以是由其他数组对象或对象属性组成的更为复杂的数据结构。从读取速度看,直接字面量与变量是非常快的,相比之下数组元素和对象属性由于需要索引,其读取速度也会因其组成结构的复杂度越高而越慢。

5.1.2 作用域和作用域链
ES6发布前JavaScript没有明确的块级作用域概念。它只有全局作用域和每个函数内的局部作用域。全局作用域就是无论此时执行的上下文是在函数内部还是函数外部的,都能访问到存在于全局作用域中的变量或对象;而定义存储在函数的局部作用域中的对象,只有在该函数内部执行上下文时才能够访问,而对函数外是不可见的。
对于能够访问到的数据,其在不同作用域中的查询也有先后顺序。这就涉及作用域链的概念。JavaScript引擎会在页面加载后创建一个全局的作用域,然后每碰到一个要执行的函数时,又会为其创建对应的作用域,最终不同的块级作用域和嵌套在内部的函数作用域,会形成一个作用域堆栈。
当前生效的作用于在堆栈的最顶端,由上往下就是当前执行上下文所能访问的作用域链。
例子:

function plus(num){
    return num +1;
}
const ret=plus(6);

函数plus的作用域链中仅有一个指向全局对象的作用域,其中包括this、函数对象plus及常量ret,而在执行到plus时,Js引擎会创建一个新的执行上下文和包含一些局部变量的活动对象。执行过程会先对num标识符进行解析,即从作用域链的最顶层依次向下查找,直至找到num标识符。

变量位于作用域链中的位置越深,被引擎访问到所需的时间就越长,所以我们应当留心对作用域链的管理。
前端性能优化:5.高性能的JavaScript代码_第1张图片

5.1.3 实战经验
1. 对局部变量的使用
如果一个非局部变量在函数中使用次数不止一次,则最好对这个局部变量进行存储。
例子:

function process(){
    const target = document.getElementById('target');
    const imgs = document.getElementById('img');
    for(let i = 0;i

函数process()中,首先通过document的两个不同的成员函数分别获取了特定的元素和元素列表,然后进行一些省略相关处理流程的操作。值得注意的是,document属于全局作用域的对象,位于作用域链最深处,在标识符解析过程中会被最后解析到。由于它在函数中使用了不止一次,所以可以考虑将其声明为一个局部变量,以提升其在作用域链中的查找顺序。
还值得注意的一点是,imgs.length执行了不止一遍。每次通过属性名或索引读取imgs的属性时,DOM都会重复执行一次对页面元素的查找,这个过程本身就会很缓慢。
改进后的代码:

function process(){
    const doc = document;
    const target = doc.getElementById('target');
    const imgs = doc.getElementById('img');
    const len = imgs.length;
    for(let i = 0;i

2. 作用域链的增长
前面讲到可以通过将频繁使用的位于较深作用域链层级中的数据,声明为局部变量来提升标识符解析与访问的速度。若能将全局变量提升到局部变量的访问高度,是否还能提升到比局部变量更高的位置呢?答案是肯定的,在当前局部变量作用域前增加新的活动变量作用域,但这种增长了作用域链的做法会造成过犹不及的效果。
比如with语句,它能将函数外层的变量提升到比当前函数局部变量还要搞的作用域链访问级别上,如下代码由于使用with的缘故,在语句中可直接访问param中的属性值,虽然方便但降低了show()函数原本局部变量的访问速度,所以应尽量少用。

const param = {
    name:'Tian',
    value:100
}
function show(){
    const content = 2;
    with(param){
        console.log('name is ${name}');
    }
}

另一个例子就是try-catch语句,catch代码块被用来处理捕获到的异常,但其中包含错误信息的error的作用域高于当前局部变量所在代码块,所以建议不要在catch语句中处理过多复杂的业务逻辑,会降低数据的访问速度。
3. 警惕闭包的使用

function mkFunc(){
    const name = 'A';
    return function showName(){
        console.log(name);
    }
}
const myFunc = mkFunc();
myFunc();

showName()函数就是一个闭包,它在mkFunc()函数执行时被创建,并能访问mkFunc()函数的局部变量name,为此便需要创建一个独立与mkFunc()函数的作用域链。
前端性能优化:5.高性能的JavaScript代码_第2张图片

一般的函数执行完成后,其中局部变量所占用的空间会被释放,但闭包的这种特性会延长父函数中局部变量的生命周期。也就意味着使用闭包可能会带来更大的内存开销及内存可能泄漏的影响。

5.2 流程控制

流程控制在业务代码中的比重是很大的,因此优化流程控制方面的代码,必然能有效地提升代码运行的速度。

5.2.1 条件判断
1. if-else和switch

通常地if-else如下:
if(value === 0){
    ......
} else if(value === 1){
    ......
} else if(value > 3 && value < 9){
    ......
}

在if-else地判断条件中,变量的取值可以是相应的离散值,也可以是不同的区间范围。
当取值全部为离散值时,可将if-else写成switch:

switch(value){
    case 0: ......; break;
    case 1:.......; break;
    case 2:......; break;
    default:......;
}

对于多个离散值的取值条件判断,switch可以清晰地表明判断条件和返回值之间的对应关系,同时也使它具有更好的代码可读性。
如果只有一两个条件的判断,通常if-else处理条件的时间会比switch更短,当判断条件多到两个以上时,switch效率更高。
2. if-else的优化
如果程序最终的执行路径时最后一个else if子语句,那么当执行到此处之前,其余所有条件判断必然都要经历一遍。耗时也会比之前所有判断条件执行耗时都久。
基于此便有了两种优化方式,第一种时开发者可以预先估计条件被匹配到的频率,按照频率的降序顺序来排列if-else语句,可以让匹配频率高的条件更快执行,从而在整体上降低程序花费在条件判断上的时间,比如

if (value === 8){
    // 匹配到8的概率最高
}else if (value === 7){
    // 匹配到7的概率仅次于8
}else if (value === 6){
    // 匹配到6的概率最低
}else {
    其他判断
}

第二种方式时利用二分法的思路,可能开发人员在编写相应的业务代码时,并不能预先估计出各种条件在多次执行时被匹配到的概率,但却能对取值区间的边界有明确的划分,那么便可以用二分取值范围来降低匹配条件的执行次数,比如

if (value < 4){
    if (value < 2){
        // 值在小于2时的情况
    }else {
        // 值在2或3之间
    }
}else {
    if (value < 6){
         // 值在4或5之间
    }else {
        //值在6到上界之间的取值  
    }
}

仅演示简单的数字区间,实际开发中需自行结合实际情况考虑。
3. 数组索引和对象属性
除了if-else和switch,利用数组的索引查询或对象的属性拆线呢也可以达到类似条件判断的目的,比如

//条件映射数组
const valueArray = [v0,v1,v2,v3,v4];
//提取对应数组索引的处理
valueArray[value];

由于数组中的每个元素既可以是对象,又可以是函数,那么便可将条件匹配的处理过程封装到数组的元素中,并用数组索引映射对应的value变量,通过匹配数组索引执行相应的处理过程。同样基于对象属性的映射方式,也能实现类似的条件查找行为,比如

//基于对象的属性映射
const valueMap = {
    'condition0': ()=>{......},
    'condition1': ()=>{......},
    'condition2': ()=>{......}
}
//提取对应对象属性的处理
valueMap[value];

基于对象属性的索引可以不局限于整数取值,它能匹配符合对象属性名命名规范的任何字符串形式,,与switch类似,其取值范围是离散值。当匹配条件的数量较小时,并不适合使用这种基于数组或对象的查找方式,因为查找数组或映射对象属性值往往比执行少量的条件判断语句要慢,只有当取值范围变得非常大时,这种查找方式的性能优势才会凸显出来。
4. 策略模式
策略模式就是定义一系列的处理流程或算法,把它们分别封装起来,使得它们可以相互替代。其目的就是将算法的使用和实现分离。
一个基于策略模式的程序通常会包含两个部分——一部分是一组策略类,其中包含一系列具体的处理算法,有点类似于包含不同处理过程的映射对象 valueMap;另一部分是环境类,它将根据上下问操作运算,决定调用策略类中的那个策略处理过程,即完成流程控制中条件匹配的部分。
假设一个具体场景:年底公司要根据员工的绩效等级发奖金,绩效考核打S的发四倍工资,打A的发三倍月工资,打B的发两倍月工资……为简化说明,仅以三种绩效考核等级为例。通常的解决方案,直接的想法是定义一个函数,接受两个参数,分别是员工的月薪和绩效考核等级,然后在其中通过if-else判断来分别计算出奖金额度:

//计算奖金的方法
function calculateBonus(salary, level){
    if(level === "S"){
        return salary*4;
    }else if(level === "A"){
        return salary*3;
    }else if(level === "B"){
        return salary*2;
    }
}

上述代码可以看出这样的实现本身没有什么问题,将所有奖金计算规则都包含在一个函数中解决。如果需要改写奖金计算规则,会发现这个函数不符合“对扩展开放,对修改封闭”的设计原则,扩展新功能的工作量不亚于推倒重做做。若重构为策略模式的写法:

//策略类
const strategies = {
    "S":(salary)=> salary*4;
    "A":(salary)=> salary*3;
    "B":(salary)=> salary*2;
}
//计算具体奖金
function calculateBonus(salary,level){
    return strategies[level](salary);
}

如此解耦了各种级别奖金计算的逻辑,如果要针对奖金发放算法进行调整,则只需修改策略类中对应的方法即可。
5. 条件判断的使用建议
· 当所要匹配的条件仅为一两个离散值时,或者容易划分不同取值范围时,使用if-else。
· 当所要匹配的条件超过一两个但少于十个离散值时,使用switch。
· 当所要匹配的条件超过十个离散值时,使用基于数组索引或对象属性的查找方式。

5.2.2 循环语句
与条件判断相比,循环语句对程序执行性能的影响更大。一个循环语句的循环执行次数直接影响程序的时间复杂度,如果代码中还存在去欸按导致循环不能及时停止,从而造成死循环,那么给用户带来的使用体验将会是非常糟糕的。
1. 三种常规循环语句
JavaScript中循环语句常见写法有三种,第一种是标准的for循环,这与大部分编程语言类似,包括初始化、循环结束条件、迭代语句及循环体四部分,第二种和第三种分别是while循环和do-while循环,二者唯一的差别就是do-while循环会先执行一遍循环体。
通常使用这三种循环语句时,基本都是对数组元素进行遍历。从索引的第一个元素开始直到数组的最后一个元素结束,每次在执行循环判断时,都需要将当前的数组索引与数组长度进行比较。由于该比较操作执行的过程中数组长度一般不会改变,且存取局部变量要比查找属性值时更省时,所以提前将要遍历的数组长度声明为局部变量,然后将该局部变量进行循环结束的条件判断,效率会更高。

//较差的循环结束判断
const array = [1,2,3,4,5];
for(let i =0;i

这在对包含较大规模DOM节点树的遍历过程中,效果会更加明显。此外还有一种更简单地提升循环语句性能的方式:将循环变量递减到0,而非递增到数组总长度。

for(let i=array.length-1;i>0;k--){
    ......
}

只有初始化时涉及到了属性值的读取,其比较的运算速度会更快。
2. for-in循环与函数迭代

//遍历object对象的所有属性
for(let prop in object){
    //确保不会遍历到object原型链上的其他对象
    if(object.hasOwnProperty(prop)){
        ......
    }
}

可以看出for-in循环能够遍历对象的属性集,特别适合处理诸如JSON对象这样的未知属性集,但对通常的循环使用场景来说,由于它遍历属性的顺序不确定,循环的结束条件也无法改变,并且因为需要从目标对象中解析出每个可枚举的属性,即要检查对象的原型和整个原型链,所以其循环速度也会比其他循环方式慢许多,若有性能要求尽量避免使用for-in循环。
对于数组的循环,JavaScript原生提供了一中forEach函数迭代的方法,此方法会遍历数组上的所有元素,并对每个元素执行一个方法,所运行的方法作为forEach的入参。
Array.forEach((value,index,arr)=>{

})

这种方式会让数组元素的迭代看起来更加直观,但在通常情况下与三种基本的循环方法相比,其性能方面仅能达到后者的1/8,如果数组长度较大或对运行速度有比较严格的要求,则函数迭代的方式不建议使用。
另外,还有ES6新加入的for-of循环,可以用它来代替for-in和forEach循环,它不仅性能比这二者更好,还支持对任何可迭代的数据结构进行遍历,但与三种常规循环语句相比其性能还是稍逊色一些。

5.2.3 递归
简单来说,递归就是函数执行体内部调用自身的行为,这种方式有时可以让复杂的算法实现变得简单,如斐波那契数列或阶乘。
使用递归也有一些潜在的问题需要注意:比如缺少或不明确递归的终止条件会很容易造成用户界面卡顿,同时由于递归是一种通过空间换时间的算法,其执行过程中会入栈保存大量的中间运算结果,对内存的开销将与递归次数成正比,由于浏览器都会限制JavaScript的调用栈大小,超出限制递归执行便会失败。
1. 使用迭代
任何递归函数都可以改写成迭代的循环形式,虽然循环会引入自身的一些性能问题,但相比于长时间执行的递归函数,其性能开销还是要小很多的。

//递归实现归并排序
function merge(left, right) {
  const result = [];
  while (left.length > 0 && right.length > 0) {
    //把最小的先取出来放到结果中
    if (left[0] < right[0]) {
      result.push(left.shift());
    } else {
      result.push(right.shift());
    }
  }
  //合并
  return result.concat(left).concat(right);
}
//递归函数
function mergeSort(array) {
  if (array.length === 1) return array;
  //计算数组中点
  const middle = Math.floor(array.length / 2);
  //分割数组
  const left = array.slice(0, middle);
  const right = array.slice(middle);
  //进行递归合并与排序
  return merge(mergeSort(left), mergeSort(right));
}

可以看出这段归并排序中,mergeSort()函数会被频繁调用,对于包含n个元素的数组来说,mergeSort()函数会被调用2n-1次,随着所处理数组元素的增多,这对浏览器的调用栈是一个严峻的考验。

//用迭代的方式改写递归函数
function mergeSort(array) {
  if (array.length === 1) return array;
  const len = array.length;
  const work = [];
  for (let i = 0; i < len; i++) {
    work.push([array[i]]);
  }
  //确保总数组长度为偶数
  if (len & 1) work.push([]);
  //迭代两两归并
  for (let lim = len; lim > 1; lim = (lim + 1) / 2) {
    for (let j = 0, k = 0; k < lim; j += 1, k += 2) {
      work[j] = merge(work[k], work[k + 1]);
      //数组长度为奇数时,补一个空数组
      if (lim & 1) work[j] = [];
    }
  }
  return work[0];
}

此处通过迭代实现的mergeSort()函数,其功能上与递归方式相同,虽然在执行时间上来看要慢一些,但它不会受到浏览器对JavaScript调用栈的限制。
2. 避免重复工作
如果在递归过程中,前一次的计算结果能被后一次计算使用,那么缓存前一次的计算结果就能有效避免许多重复工作。比如阶乘操作:

//计算某个数的阶乘
function factorial(n){
    if(n === 0){
        return 1;
    }else{
        return n*factorial(n-1);
    }
}

当我们计算多个数的阶乘(如2、3、4)时,如果分别计算这三个数的阶乘,则函数factorial()总共要被调用12次,其中国在计算4的阶乘时,会把3的阶乘重新计算一遍,计算3的阶乘时又会把2的阶乘重新计算一遍,可以看出如果在计算4的阶乘之前,将3的阶乘数缓存下来,那么在计算4的阶乘时,递归仅需要再执行一次。如此便通过缓存阶乘计算结果,避免多于计算过程,原本12次的递归调用,可以减少到5次。
如:

function memoize(func,cache){
    const cache = cache || {};
    return function(args){
        if(!cache.hasOwnProperty(args)){
            cache[args] = func(args);
        }
        return cache[args];
    }
}

该方法利用函数闭包有效避免了类似计算多次阶乘时的重复操作,确保只有当一个计算在之前从未发生过时,才产生新的计算值,这样前面的阶乘函数便可改写为:

const memorizeFactorial = memorize(factorial,{'0':1,'1':1});

这种方式也存在性能问题,比如函数闭包延长了局部变量的存活期,如果数据量过大又不能有效回收,则容易导致内存溢出。这种方案只有在程序中有相同参数多次调用时才会比较省时,所以综合而言,优化方案还需根据具体使用场景具体考虑。

5.3 字符串处理

为了搞笑处理字符串,使用正则表达式是必不可少的,但两个匹配同一文本的正则表达式并不意味着它们具有相同的执行速度。

5.3.1 字符串拼接
字符串拼接是前端开发中的常规操作,但在大规模数据的循环迭代中进行字符串拼接时,可能稍有不慎就会造成严重的性能问题。
几种常见的拼接方式:

//使用"+"运算符
const str1 = "a" + "b";
//使用"+="运算符
const str2 = "a";
str2 += "b";
//使用数组的join()方法
const str3 =["a","b"].join();
//使用字符串的concat()方法
const str4 = "a";
str4.concat("b");

当处理少量单次或少量字符串拼接时,这些方法的运行速度都很快,根据自己偏好使用即可,但随着需要迭代合并的字符串数量增加,他们之间性能的差异逐渐显现,如下是一个字符串迭代拼接的处理过程:

let len = 1000;
let str = "";
while(len--){
    str += "a" + "b";
}

但看循环内部的字符串拼接操作,其代码运行过程可分为四步:首先在内部创建一个临时的字符串变量,然后将拼接的字符串"ab"赋值给它,接着把该临时变量与str的当前值进行拼接,最后将结果赋值给str。可见由于存在临时变量的存取,其性能并不满足预期,若避免临时变量存取直接向str变量上拼接,在大部分浏览器中,都能将这一操作步骤的执行速度提升20%左右。
//不生产中间临时变量的字符串拼接
str = str + “a” + “b”;

数组对象的 join()方法和字符串对象的concat()方法比使用赋值表达式实现字符串拼接在性能上稍慢。

5.3.2 正则表达式
1. 正则表达式处理步骤
(1) 编译表达式:一个正则表达式对象可以通过RegExp构造函数创建,也可以定义成正则直接量,档期被创建出来后,浏览器会先去验证然后将它转化为一个原生待程序,用于执行匹配任务。
(2) 设置起始位置:当匹配开始时,需要先确定目标字符串的其实搜索位置,初始查询时为整个字符串的起始字符的位置,在回溯查询时为正则表达式对象的lastIndex属性指定的索引位置。
(3) 匹配过程:在确定了起始位置后,便会从左到右逐个测试正则表达式的各组成部分,看能否找到匹配的字元。如果遇到表达式中的量词和分支,则需要进行决策,对于量词(*、+或{3}),需要判断从何时开始进行更多字符的匹配尝试;对于分支("|"或操作),每次需从选项中选择一个分支进行接下来的匹配。在正则表达式做这种决策的时候,会进行记录以备回溯时使用。
(4) 匹配结束:若当前完成一个字元的匹配,则正则表达式会继续向右扫描,如果接下来的部分也都能匹配上,则宣布匹配成功并结束匹配;若当前字元匹配不到,或者后续字元匹配失败,则会回溯到上一个决策点选择余下可选字元继续匹配过程,直到匹配到目标子字符串,宣布匹配成功,或者尝试了所有排列组合后也没找到。宣布匹配失败,结束本轮匹配。回到起始字符串的下一个字符,重复匹配过程。
2. 分支与重复
看看正则表达式在匹配过程中是如何处理分支重复的:

/<(img|p)>.*<\img>/.test("

")

开始匹配时,首先从左向右查找<字符,恰好目标字符串的第一个字符时<,然后进行img|p分支子表达式的处理,分支选择也是从左到右的,先检查img是否能匹配成功,发现字符<随后的字符p并不能匹配,此分支无法继续。需要回溯到最近一次的分支决策点,即首字母<的后面,尝试第二个分支p字符的匹配,发现匹配成功。
接下来的.号标识匹配除换行符外的任意字符,并且带有量词符号*,这是一个贪婪量词,需要重复0次或多次的匹配.号,由于目标字符串中不存在换行符,所以它会过滤掉接下来的所有字符,至字符串尾部往回继续匹配接下来的字元<\/img>,最后一个字符为>,不匹配所需的<,尝试倒数第二个字符p,p也不匹配,如此循环知道匹配到目标字元或找不到目标字元匹配失败。
如果我们仅想查找距离字元<(img|p)>最近的<\/img>,显然这种贪婪量词的搜索过程会扩大正则表达式的匹配空间,为此可以使用惰性量词.*?进行替换。
可以看出这里的目标字符串,对于贪婪量词与惰性量词的正则匹配结果是相同的,但它们的匹配过程却是不同的,所以当目标字符串变得非常大时,获得相同匹配结果的正则表达式,其执行性能可能会存在较大差异。
3. 回溯失控
当某个正则表达式的执行使浏览器卡顿数秒或更长时间,可能出现了回溯失控。如下:

/.*?.*?.*?<\/title>.*?<\/head>.*?<body>.*?<\/body>.*?<\/html>/
</code></pre> 
  <p>该正则表达式在匹配常规html文件时不会存在运行问题,但如果碰到一些必要的html标签缺失,那么其匹配效率或变得非常糟糕。比如当html文件中缺少结束标签<code></html></code>时,在匹配最后一个惰性量词后并未能找到符合字元<code><\/html></code>的字符串,此时正则表达式并不会结束,而是向前回溯到上一次的惰性量词出,继续字元<code><\/body></code>的匹配,以试图找到第二个<code></body></code>标签。如果没有找到,则会一次继续向前回调,可想而知这样的查询性能会很低。<br> 如何解决?首先可以想到具体化模糊字元,比如将.<em>?具体化为[^\r\n]</em>,进而去除集中回溯时可能发生的情况。虽然这种方式控制了可能的回溯失控,但在匹配不完整html文件时所需时间依然喝文件大小成线性关系,所以性能并没有得到有效提高。<br> 更为有效的方式时预查找,它作为全局匹配的一部分,能够仅检查自己所包含的正则表达式字元于当前位置是否能够匹配,并且不消耗字符,即在一个匹配发生后立即开始下一次匹配搜索,而非从包含预查找的字符后开始。预查找的形式是:(?=pattern),pattern代表一个正则表达式,改写上面的例子:</p> 
  <pre><code>/<html>(?=(.*?<head>))\1(?=(.*?<title>))\2(?=(.*?<\/title>))\3(?=(.*?<\/head>))\4(?=(.*?<body>))\5(?=(.*?<\/body>))\6.*?<\/html>/
</code></pre> 
  <p>这样当html问而建结尾部分缺少<code></html></code>标签时,最后的惰性量词.*?会展开至整个字符串末尾,由于没有有效回溯点,所以正则表达式会立即宣布失败。<br> 4. 量词嵌套<br> 另一个可能会引起回溯失控的写法就是量词嵌套,即在一个整体被量词修饰的组中有量词的使用,如:对一个包含大量T字符的字符串使用如下正则表达式进行匹配:</p> 
  <pre><code>/(T+T+)+Q/
</code></pre> 
  <p>这种排列组合会产生数量巨大的查找分支。为防止这种情况的发生,关键要确保正则表达式不对字符串相同的部分进行匹配,并且尽量保持正则表达式简洁易懂,可以改写为:<code>/TT+Q/</code>,但对于较复杂的正则表达式可能难以避免,必要时可采取预查找进行规避。</p> 
  <p><strong>5.3.3 优化正则表达式</strong><br> 一些有效提升正则表达式匹配效率的方法:</p> 
  <ol> 
   <li>化繁为简:大规模的单一正则表达式很呐维护,并且容易出现回溯失控的问题。可使用条件逻辑将复杂的字符串搜索问题拆分为多个正则表达式来解决。</li> 
   <li>将正则表达式赋值给变量:复用时可以避免重新编译。</li> 
   <li>合适的量词:使用合适的量词可以有效提升性能。</li> 
   <li>更快失败:通常正则表达式执行较慢不是其匹配成功较慢,而是匹配失败的过程较慢。若想让正则表达式更快执行完毕,应加快其失败的过程。</li> 
   <li>尽量具体:对于子表达式能够重叠匹配或字符与字元相邻时,正则表达式的可能分支路径会增加,所以表达式应更加具体化。</li> 
   <li>减少分支数量:正则表达式中,使用类似按位或的竖线符号|来表示分支选型,但通常建议尽量减少分支的使用,可以使用字符集或选项数组来代替,因为字符集在切换选项时使用的时位向量的方式,这笔分支采用的回溯快。示例:</li> 
  </ol> 
  <table> 
   <thead> 
    <tr> 
     <th>分支方式</th> 
     <th>字符集</th> 
    </tr> 
   </thead> 
   <tbody> 
    <tr> 
     <td>bat\mat</td> 
     <td>[bm]at</td> 
    </tr> 
    <tr> 
     <td>red\read</td> 
     <td>rea?d</td> 
    </tr> 
    <tr> 
     <td>(.|\r|\n)</td> 
     <td>[\s\S]</td> 
    </tr> 
   </tbody> 
  </table> 
  <p>注意采用非捕获组:由于捕获组需要记录反向引用,会更加消耗内存和引用。比如可以使用(?:pattern)代替(pattern)。<br> 使用反向引用避免后处理:如果使用场景需要引用匹配的一部分,则应尽量用捕获组捕获目标片段,然后通过反向引用进一步处理,而不是剥离出目标字符串后再手动处理。</p> 
  <h3>5.4 快速响应</h3> 
  <p>JavaScript代码的执行通常会阻塞页面的渲染,考虑到用户体验,这就会限制我们在编写代码时需要注意减少或避免一些执行时间过长的逻辑运算。</p> 
  <p><strong>5.4.1 浏览器的限制</strong><br> 由于JavaScript是单线程,这就意味着浏览器的每个窗口或页签在同一时间内,要么执行JavaScript脚本,要么响应用户操作刷新页面,也就是说这二者的行为是相互阻塞的。<br> 对于浏览器的这种限制,我们可能就需要对长时间运行的脚本进行重构,尽量保证一段脚本的执行不超过100ms,若果超过这个时间阈值,用户明显就会网站卡顿变慢的使用体验。<br> 引起JavaScript执行时间过长的原因概括有三点:<br> 第一类是对DOM的频繁操作,相比于JavaScript的运算,DOM操作的开销都是极高的,这也是现代前端框架中普遍采取虚拟DOM的原因。<br> 第二类是不恰当的循环,可能因为循环次数执行过多,或者每次循环中执行了过多操作,若能将功能尽可能分解就会明显缓解这个问题。<br> 第三类是存在过深的递归,前面章节有提到过浏览器对JavaScript调用栈存在限制,将递归改写成迭代能有效地避免此类问题。</p> 
  <p><strong>5.4.2 异步队列</strong><br> JavaScript既要处理运算又要响应与用户的交互,就是通过异步队列完成的。<br> 当创建一个异步任务时,它其实并没有马上执行,而是被JavaScript引擎放置到了一个队列中,当执行完成一个任务脚本后,JavaScript引擎便会挂起让浏览器去做其他工作,比如更新页面,当页面更新完后JavaScript引擎便会查看此异步队列,并从中取出一个任务脚本去执行,只要该队列不为空,这个过程就会不断重复。<br> 故此便有了对执行过长任务的一种优化策略,即将一个长任务拆分为多个异步任务,从而让浏览器给刷新页面留出时间,但过短的延迟时间也可能会让浏览器响应不及时,通常可以用定时器来控制一个100ms左右的延迟。</p> 
  <h3>5.5 其他建议</h3> 
  <p>除了前面的几种方法,还有些小技巧也能帮助浏览器高效执行JavaScript,比如避免多重求值、使用位操作及使用原生方法。</p> 
  <p><strong>5.5.1 避免多重求值</strong><br> 多重求值是脚本语言中普遍存在的一种语法特性,即动态执行包含可执行代码的字符串,虽然当前的主流前端项目很少会有类似的方法,但如果面临优化历史代码的场景,就需要对此多加留意。能够运行代码字符串的方法通常有如下四种:setTimeout()、setInterval()、eval()及Function()构造函数。</p> 
  <pre><code>const a = 1, b = 2;
let result = 0;
//使用setTimeout() 函数执行代码字符串
setTimeout("result = a + b", 100);
//使用setInterval() 函数执行代码字符串
setInterval("result = a + b", 100);
//使用eval() 函数执行代码字符串
result = eval("a + b");
//使用Function() 函数执行代码字符串
result = new Function("a", "b", "return a + b");
</code></pre> 
  <p>这四段代码的执行过程,首先会以正常的方式进行求值,接着在执行过程中对字符串里的代码进行一次额外的求值运算,这个运算操作的代价,与直接执行字符串中代码的代价相比时巨大的。在开发中应当避免使用Function()与eval()函数,同时切记在使用setTimeout()和setInterval()函数时第一个参数使用字符串。</p> 
  <p><strong>5.5.2 使用位操作</strong><br> 几乎在所有编程语言中,微操作的执行速度都是非常快的,因为位操作通常发生在系统底层。在JavaScript中使用有符号的32位二进制来表示一个数字,位操作就是直接按照二进制方式进行计算的,这要比其他数学运算和布尔操作快得多。</p> 
  <p><strong>5.5.3 使用原生方法</strong><br> 使用位操作来优化数学运算的场景也是比较有限的,面对复杂的数学运算时可以多使用JavaScript的原生方法。<br> 常用的原生方法:</p> 
  <table> 
   <thead> 
    <tr> 
     <th>属性\方法</th> 
     <th>含义</th> 
    </tr> 
   </thead> 
   <tbody> 
    <tr> 
     <td>Math.abs(num)</td> 
     <td>计算num的绝对值</td> 
    </tr> 
    <tr> 
     <td>Math.pow(num,power)</td> 
     <td>计算num的power次幂</td> 
    </tr> 
    <tr> 
     <td>Math.sqrt(num)</td> 
     <td>计算num的平方根</td> 
    </tr> 
    <tr> 
     <td>Math.exp(num)</td> 
     <td>计算自然对数底的指数</td> 
    </tr> 
    <tr> 
     <td>Math.cos(x)</td> 
     <td>计算余弦函数</td> 
    </tr> 
    <tr> 
     <td>Math.PI</td> 
     <td>计算圆周率</td> 
    </tr> 
    <tr> 
     <td>Math.SQRT2</td> 
     <td>计算2的平方根</td> 
    </tr> 
   </tbody> 
  </table> 
  <h3>5.6 小结</h3> 
  <p>从代码书写角度介绍了许多与前端性能相关的内容,包括数据存取、流程控制、字符串处理、不阻塞页面渲染流程的快速响应。以及能让JavaScript执行更快的一些技巧。<br> 同时详细介绍了如何优化正则表达式,从执行过程到回溯失控以及相关的一些优化注意事项都有介绍。</p> 
  <p>前端性能优化系列:<br> 前端性能优化:1.什么是前端性能优化<br> 前端性能优化:2.前端页面的生命周期<br> 前端性能优化:3.图像资源优化<br> 前端性能优化:4.资源加载优化<br> 前端性能优化:5.高性能的JavaScript代码<br> 前端性能优化:6.项目构建优化<br> 前端性能优化:7.页面渲染优化</p> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1723007241986060288"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(前端性能优化,javascript,前端,性能优化)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1903150050603757568.htm"
                           title="探究Three.js中模型移动与旋转的交互逻辑" target="_blank">探究Three.js中模型移动与旋转的交互逻辑</a>
                        <span class="text-muted">Front_Yue</span>
<a class="tag" taget="_blank" href="/search/3D%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/1.htm">3D技术实践指南</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/three.js/1.htm">three.js</a><a class="tag" taget="_blank" href="/search/3d/1.htm">3d</a>
                        <div>前言Three.js作为一个功能强大的JavaScript3D库,极大地简化了在网页上创建和展示3D图形的过程。它在游戏开发、产品展示、虚拟现实等众多领域都被广泛应用。通过Three.js,开发者能够轻松创建出复杂的三维场景和交互性强的3D应用,为用户带来沉浸式的体验。一、模型移动的交互逻辑实现(一)键盘控制模型移动利用键盘事件来控制模型在三维空间中的位置移动,是一种常见且便捷的交互方式。以下为具</div>
                    </li>
                    <li><a href="/article/1903149797905330176.htm"
                           title="从零开始:使用原生JS打造简易飞机大战游戏" target="_blank">从零开始:使用原生JS打造简易飞机大战游戏</a>
                        <span class="text-muted">西域情歌</span>

                        <div>本文还有配套的精品资源,点击获取简介:在本教程中,我们将探讨如何利用原生JavaScript的特性,包括事件处理、DOM操作、定时器和音频处理,来构建一个基础的“飞机大战”游戏。该游戏的核心元素包括玩家飞机、敌机、子弹和碰撞检测,它们通过HTML和CSS展现在页面上。通过编写JavaScript脚本,我们实现游戏对象的创建与状态管理,响应用户的键盘和点击事件,更新游戏内容,并通过定时器维护游戏循环</div>
                    </li>
                    <li><a href="/article/1903141222185234432.htm"
                           title="React 18 如何定义变量,及赋值 与渲染" target="_blank">React 18 如何定义变量,及赋值 与渲染</a>
                        <span class="text-muted">痴心阿文</span>
<a class="tag" taget="_blank" href="/search/React/1.htm">React</a><a class="tag" taget="_blank" href="/search/react.js/1.htm">react.js</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>React18中,定义变量、赋值和渲染的方式因变量的用途和作用域不同而有所差异,下面为你详细介绍不同场景下的实现方法。1.函数组件内定义普通变量在函数组件里,你可以像在普通JavaScript函数中一样定义变量,并且这些变量会在每次组件重新渲染时重新创建。importReactfrom'react';constMyComponent=()=>{//定义普通变量并赋值constmessage='He</div>
                    </li>
                    <li><a href="/article/1903138952362127360.htm"
                           title="使用Three.js渲染器创建炫酷3D场景" target="_blank">使用Three.js渲染器创建炫酷3D场景</a>
                        <span class="text-muted">Front_Yue</span>
<a class="tag" taget="_blank" href="/search/3D%E6%8A%80%E6%9C%AF%E5%AE%9E%E8%B7%B5%E6%8C%87%E5%8D%97/1.htm">3D技术实践指南</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/three.js/1.htm">three.js</a><a class="tag" taget="_blank" href="/search/3d/1.htm">3d</a>
                        <div>引言在当今数字化的时代,3D图形技术正以其独特的魅力在各个领域掀起波澜。从影视制作到游戏开发,从虚拟现实到网页交互,3D场景以其强烈的视觉冲击力和沉浸式的体验,成为了吸引用户、传达信息的重要手段。而Three.js,作为一款功能强大且广受欢迎的JavaScript3D库,为我们提供了便捷、高效的途径来创建令人炫目的3D场景。本文将深入探讨使用Three.js渲染器创建炫酷3D场景的方方面面,带领读</div>
                    </li>
                    <li><a href="/article/1903138070908170240.htm"
                           title="asp.net mvc mysql 开源项目_【开源项目SugarSite】ASP.NET MVC+ Layui+ SqlSugar+RestSharp项目讲解..." target="_blank">asp.net mvc mysql 开源项目_【开源项目SugarSite】ASP.NET MVC+ Layui+ SqlSugar+RestSharp项目讲解...</a>
                        <span class="text-muted">weixin_39805732</span>
<a class="tag" taget="_blank" href="/search/asp.net/1.htm">asp.net</a><a class="tag" taget="_blank" href="/search/mvc/1.htm">mvc</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/1.htm">开源项目</a>
                        <div>SugarSite一个前端支持移动端的企业网站,目前只支持了简单功能,后续还会加上论坛等。源码GIT地址:技术介绍Layui个人而言不喜欢引用一堆东西,越简洁越好,layui正好能够满足我的这种需求,它是一款轻量级UI,JS部分都是采用模块化设计(AMD),对移动端支持比较不错。唯一不足是目前支持的组件有些少,需要有一定前端扩展能力的人才可以顺心使用。用法:例如我想用form.js和uploda.</div>
                    </li>
                    <li><a href="/article/1903133760161902592.htm"
                           title="一个后端工程师对前端云 Vercel 的体验和探索" target="_blank">一个后端工程师对前端云 Vercel 的体验和探索</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/%E7%A8%8B%E5%BA%8F%E5%91%98/1.htm">程序员</a>
                        <div>今天小猿姐特邀咱们资深的程序猿为大家带来产品的体验报告。Vercel概述Vercel是一个为前端开发者设计的一体化平台(前端云),可以帮助开发者快速地将网站和应用程序部署到各种环境中,并且提供了一个灵活、可扩展和安全的平台,非常适合开发者在不同平台和环境中进行开发和部署。Vercel的主要特点包括:通过自动配置构建设置和提供详细的构建日志,简化了部署管理过程。借助集成的CI/CD功能,开发者可以预</div>
                    </li>
                    <li><a href="/article/1903130231766577152.htm"
                           title="HarmonyOS5开发:Ark-TS 深度解析:从状态管理到性能优化,揭秘鸿蒙开发的底层逻辑" target="_blank">HarmonyOS5开发:Ark-TS 深度解析:从状态管理到性能优化,揭秘鸿蒙开发的底层逻辑</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/harmonyos-next/1.htm">harmonyos-next</a>
                        <div>Ark-TS作为鸿蒙生态的核心开发语言,其设计哲学和技术细节值得让我们一起深入挖掘以下下。这篇文章将会带您和我们一起聚焦Ark-TS的状态管理机制、类型系统优化及声明式UI的底层实现,通过代码示例和原理分析,带您揭开Ark-TS高效开发的神秘面纱。一、状态管理:Ark-TS的“神经中枢”在Ark-TS中,状态管理是驱动UI更新的核心机制。不同的状态装饰器(如@State、@Prop、@Link)各</div>
                    </li>
                    <li><a href="/article/1903115499265388544.htm"
                           title="04.文本标签" target="_blank">04.文本标签</a>
                        <span class="text-muted">龙哥带你学编程</span>
<a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a>
                        <div>一、文本简介1、页面组成元素1)以淘宝购物官网为例,分析网页:在淘宝购物官网的首页上,我们可以看到它是由超链接,文字,图片等元素构成。2)页面组成元素①一个静态页面绝大部分由以下四种元素组成:文本图片超链接音频和视频②思考:符合以下特点的网页是静态还是动态页面?带有音频和视频带有flash动画带有css动画带有JavaScript特效不是。动态页面和静态页面区别在于:是否用到了后端技术,以及是否与</div>
                    </li>
                    <li><a href="/article/1903114109897994240.htm"
                           title="DeepSeek 模型未来怎么走?技术创新、行业落地全解析!" target="_blank">DeepSeek 模型未来怎么走?技术创新、行业落地全解析!</a>
                        <span class="text-muted">网罗开发</span>
<a class="tag" taget="_blank" href="/search/AI/1.htm">AI</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%A8%A1%E5%9E%8B/1.htm">大模型</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/%E8%81%8C%E5%9C%BA%E5%92%8C%E5%8F%91%E5%B1%95/1.htm">职场和发展</a>
                        <div>网罗开发(小红书、快手、视频号同名)  大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、HarmonyOS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。图书作者:《ESP32-C3物联网工程开发实战》图书作者:《SwiftUI入门,进阶与实战》超级个体:CO</div>
                    </li>
                    <li><a href="/article/1903103515111256064.htm"
                           title="SvelteKit 最新中文文档教程(6)—— 状态管理" target="_blank">SvelteKit 最新中文文档教程(6)—— 状态管理</a>
                        <span class="text-muted">冴羽yayujs</span>
<a class="tag" taget="_blank" href="/search/Svelte/1.htm">Svelte</a><a class="tag" taget="_blank" href="/search/%E4%B8%AD%E6%96%87%E6%96%87%E6%A1%A3/1.htm">中文文档</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E6%A1%86%E6%9E%B6/1.htm">前端框架</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/react/1.htm">react</a><a class="tag" taget="_blank" href="/search/svelte/1.htm">svelte</a><a class="tag" taget="_blank" href="/search/sveltekit/1.htm">sveltekit</a>
                        <div>前言Svelte,一个语法简洁、入门容易,面向未来的前端框架。从Svelte诞生之初,就备受开发者的喜爱,根据统计,从2019年到2024年,连续6年一直是开发者最感兴趣的前端框架No.1:Svelte以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构建轻量级Web项目。为了帮助大家学习Svelte,我同时搭建了Svelte最新的中文文档站点。如果需要进阶学习,也可以入手我</div>
                    </li>
                    <li><a href="/article/1903103388736876544.htm"
                           title="MTK ADSP" target="_blank">MTK ADSP</a>
                        <span class="text-muted">yyc_audio</span>
<a class="tag" taget="_blank" href="/search/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%A1%AC%E4%BB%B6/1.htm">嵌入式硬件</a>
                        <div>MTK音频硬件概念AFE:音频前端硬件audiofrontendhwAFEMEMIF(FE):PCMDMA,memoryread/writeAudiointerconnection:connectionfabricforaudiosubmodule。核心路由器件。负责FE和BE之间的连接和路由。DAI(BE):DigitalAudioI/F,eTDM/I2S/DMIC.–EnhancedTDM,c</div>
                    </li>
                    <li><a href="/article/1903095945579524096.htm"
                           title="《今日AI-人工智能-编程日报》-源自2025年3月19日" target="_blank">《今日AI-人工智能-编程日报》-源自2025年3月19日</a>
                        <span class="text-muted">小亦编辑部</span>
<a class="tag" taget="_blank" href="/search/%E6%AF%8F%E6%97%A5AI-%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD-%E7%BC%96%E7%A8%8B%E6%97%A5%E6%8A%A5/1.htm">每日AI-人工智能-编程日报</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>1.豆包AI编程功能迎来三项重磅升级豆包平台今日宣布其AI编程功能迎来三项重要升级,包括:HTML实时预览:支持用户在编写HTML代码时实时查看网页效果,显著提升前端开发效率,尤其适用于小游戏和网页制作。Python代码直接运行与一键修复:用户可直接运行Python代码,并在出错时一键修复,极大降低了编程门槛,提升了开发效率。生成完整项目:新增生成完整项目的功能,帮助用户快速创建应用程序,缩短开发</div>
                    </li>
                    <li><a href="/article/1903089639758032896.htm"
                           title="50个常见的python毕业设计/课程设计(源码+文档)" target="_blank">50个常见的python毕业设计/课程设计(源码+文档)</a>
                        <span class="text-muted">冷琴1996</span>
<a class="tag" taget="_blank" href="/search/Python%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/1.htm">Python系统设计</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E8%AF%BE%E7%A8%8B%E8%AE%BE%E8%AE%A1/1.htm">课程设计</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>计算机课程设计/毕业设计指南,为计算机相关专业毕业生提供源码、数据库安装、远程调试等相关服务,提供功能讲解视频。下面是50个基于python/django/vue的毕业设计/课程设计。1.网上商城系统这是一个基于python+vue开发的商城网站,平台采用B/S结构,后端采用主流的Python语言进行开发,前端采用主流的Vue.js进行开发。整个平台包括前台和后台两个部分。前台功能包括:首页、商品</div>
                    </li>
                    <li><a href="/article/1903082066069745664.htm"
                           title="UI自动化测试往往在功能测试之后进行的核心原因" target="_blank">UI自动化测试往往在功能测试之后进行的核心原因</a>
                        <span class="text-muted">豌豆射手^</span>
<a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95/1.htm">测试</a><a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a><a class="tag" taget="_blank" href="/search/%E5%8A%9F%E8%83%BD%E6%B5%8B%E8%AF%95/1.htm">功能测试</a>
                        <div>一、流程效率:避免“过早优化浪费资源”1.功能未定型,频繁修改导致脚本维护成本高实际场景:某电商平台开发初期,前端页面按钮的ID因需求变动频繁更改。此时若投入UI自动化,需不断调整元素定位逻辑,甚至完全重写脚本。对比分析:阶段功能测试方式成本对比开发初期手动功能测试人工快速验证,适应变化,成本低。稳定期UI自动化测试代码维护成本高,反复修改会抵消效率收益。2.瀑布模型与敏捷开发的差异瀑布模型:严格</div>
                    </li>
                    <li><a href="/article/1903081058404986880.htm"
                           title="前端如何实现分页?" target="_blank">前端如何实现分页?</a>
                        <span class="text-muted">小智玩前端</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91/1.htm">前端开发</a><a class="tag" taget="_blank" href="/search/%E5%88%86%E9%A1%B5/1.htm">分页</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%88%AA%E5%8F%96/1.htm">数据截取</a><a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E7%BB%84%E6%93%8D%E4%BD%9C/1.htm">数组操作</a>
                        <div>先定义分页中需要用的三个值:currentPage(当前页码)、total(总条数)、pageSize(每页展示的数据量)分页的思路:把所有的数据请求回来后,通过arr.slice(开始索引,结束索引)来进行截取每一页的数据;假设当前页是currentPage=1,pageSize=5,那么应该从(currentPage-1)*pageSize开始截取,到currentPage*pageSize结</div>
                    </li>
                    <li><a href="/article/1903075262237569024.htm"
                           title="9种JavaScript数组去重的高阶方法" target="_blank">9种JavaScript数组去重的高阶方法</a>
                        <span class="text-muted">2501_90226133</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a>
                        <div>给定一个数组[1,2,2,4,null,null,‘3’,‘abc’,3,5,4,1,2,2,4,null,null,‘3’,‘abc’,3,5,4]去除重复项。letarr=[1,2,2,4,null,null,‘3’,‘abc’,3,5,4,1,2,2,4,null,null,‘3’,‘abc’,3,5,4]1、利用对象的key唯一众所周知,对象的key不可重复,否则后者将覆盖前者。利用该特性</div>
                    </li>
                    <li><a href="/article/1903073090431152128.htm"
                           title="Ark-TS 语言:鸿蒙生态的高效开发利器,让我们用大白话说一说" target="_blank">Ark-TS 语言:鸿蒙生态的高效开发利器,让我们用大白话说一说</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/harmonyos-next/1.htm">harmonyos-next</a>
                        <div>Ark-TS(华为专门为鸿蒙系统——就是华为自己的手机、平板、智能设备操作系统——设计的编程语言,基于TypeScript,一种比普通JavaScript更严格、能减少错误的语言)是鸿蒙应用开发的主力工具。它就像给开发者配备了一套趁手的工具包,让写代码又快又稳。简单来说,Ark-TS有几个厉害的地方:静态类型检查(写代码时必须给变量指定类型,比如数字、文字,这样电脑能在运行前就发现类型错误,避免程</div>
                    </li>
                    <li><a href="/article/1903070434291675136.htm"
                           title="单例模式实现" target="_blank">单例模式实现</a>
                        <span class="text-muted"></span>
<a class="tag" taget="_blank" href="/search/%E5%90%8E%E7%AB%AF/1.htm">后端</a>
                        <div>一、是什么单例模式(SingletonPattern):创建型模式,提供了一种创建对象的最佳方式,这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建在应用程序运行期间,单例模式只会在全局作用域下创建一次实例对象,让所有需要调用的地方都共享这一单例对象,如下图所示:二、实现在javascript中,实现一个单例模式可以用一个变量来标志当前的类已经创建过对象,如果下次获取当</div>
                    </li>
                    <li><a href="/article/1903063651842060288.htm"
                           title="JavaScript HTML DOM 节点列表" target="_blank">JavaScript HTML DOM 节点列表</a>
                        <span class="text-muted">宇哥资料</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>NodeList对象是一个从文档中获取的节点列表(集合)。NodeList对象类似HTMLCollection对象。一些旧版本浏览器中的方法(如:getElementsByClassName())返回的是NodeList对象,而不是HTMLCollection对象。所有浏览器的childNodes属性返回的是NodeList对象。大部分浏览器的querySelectorAll()返回NodeLis</div>
                    </li>
                    <li><a href="/article/1903062518021025792.htm"
                           title="js知识点-拓展运算符和剩余运算符" target="_blank">js知识点-拓展运算符和剩余运算符</a>
                        <span class="text-muted">lmryBC49</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/ecmascript/1.htm">ecmascript</a>
                        <div>概述在现代JavaScript开发中,ES6引入的拓展运算符(SpreadOperator)和剩余运算符(RestOperator)让代码更加简洁和灵活。无论是数组、对象的拆分与合并,还是函数参数的处理,这两个运算符都是非常实用的工具。拓展运算符1.什么是拓展运算符?拓展运算符(SpreadOperator)由三个连续的点...表示,用于将一个可迭代对象(例如数组、字符串等)展开成多个元素。拓展运</div>
                    </li>
                    <li><a href="/article/1903050155028967424.htm"
                           title="Vue.js 中的 Memoization:提升性能的缓存技术" target="_blank">Vue.js 中的 Memoization:提升性能的缓存技术</a>
                        <span class="text-muted">vvilkim</span>
<a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>在现代前端开发中,性能优化是一个永恒的话题。随着应用规模的增大,复杂的计算和频繁的函数调用可能会导致性能瓶颈。Vue.js作为一个流行的前端框架,提供了多种优化手段,其中memoization(记忆化)就是一种非常有效的技术。本文将详细介绍Vue.js中的memoization,以及如何利用它来提升应用性能。什么是Memoization?Memoization是一种优化技术,通过缓存函数的结果来避</div>
                    </li>
                    <li><a href="/article/1903050152067788800.htm"
                           title="Vue.js 性能优化:虚拟 DOM 与虚拟滚动" target="_blank">Vue.js 性能优化:虚拟 DOM 与虚拟滚动</a>
                        <span class="text-muted">vvilkim</span>
<a class="tag" taget="_blank" href="/search/vue/1.htm">vue</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a>
                        <div>在现代前端开发中,性能优化是一个永恒的话题。Vue.js作为一款流行的前端框架,提供了许多强大的工具和技术来提升应用的性能。其中,虚拟DOM和虚拟滚动是两个非常重要的概念。本文将深入探讨它们的原理、优势以及如何在Vue.js中使用它们来优化性能。什么是虚拟DOM?虚拟DOM(VirtualDOM)是Vue.js用于提升性能的核心技术之一。它是一个轻量级的JavaScript对象树,用于表示真实DO</div>
                    </li>
                    <li><a href="/article/1903044105169072128.htm"
                           title="用python执行js代码:PyExecJS库详解" target="_blank">用python执行js代码:PyExecJS库详解</a>
                        <span class="text-muted">数据知道</span>
<a class="tag" taget="_blank" href="/search/2025%E5%B9%B4%E7%88%AC%E8%99%AB%E5%92%8C%E9%80%86%E5%90%91%E6%95%99%E7%A8%8B/1.htm">2025年爬虫和逆向教程</a><a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E9%87%87%E9%9B%86/1.htm">数据采集</a><a class="tag" taget="_blank" href="/search/nodejs/1.htm">nodejs</a>
                        <div>更多内容请见:爬虫和逆向教程-专栏介绍和目录文章目录1.介绍和安装1.1PyExecJS介绍1.2安装JavaScript运行时1.3安装PyExecJS2.PyExecJS的基本使用2.1执行简单的JavaScript代码2.2使用外部JavaScript文件2.3先编译、后调用2.4传递参数和获取返回值3.PyExecJS的高级功能3.1指定JavaScript运行时3.2处理异步JavaSc</div>
                    </li>
                    <li><a href="/article/1903032506702163968.htm"
                           title="JAVA毕业设计BS架构考研交流学习平台设计与实现计算机源码+lw文档+系统+调试部署+数据库" target="_blank">JAVA毕业设计BS架构考研交流学习平台设计与实现计算机源码+lw文档+系统+调试部署+数据库</a>
                        <span class="text-muted">瑞致网络</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/jvm/1.htm">jvm</a>
                        <div>JAVA毕业设计BS架构考研交流学习平台设计与实现计算机源码+lw文档+系统+调试部署+数据库JAVA毕业设计BS架构考研交流学习平台设计与实现计算机源码+lw文档+系统+调试部署+数据库本源码技术栈:项目架构:B/S架构开发语言:Java语言开发软件:ideaeclipse前端技术:Layui、HTML、CSS、JS、JQuery等技术后端技术:JAVA运行环境:Win10、JDK1.8数据库:</div>
                    </li>
                    <li><a href="/article/1903030992545837056.htm"
                           title="5-1 使用ECharts将MySQL数据库中的数据可视化" target="_blank">5-1 使用ECharts将MySQL数据库中的数据可视化</a>
                        <span class="text-muted">上课的牛马</span>
<a class="tag" taget="_blank" href="/search/%E5%AE%9E%E8%AE%AD/1.htm">实训</a><a class="tag" taget="_blank" href="/search/%E5%A4%A7%E6%95%B0%E6%8D%AE/1.htm">大数据</a>
                        <div>方法一:使用PythonFlask框架搭建API对于技术小白来说,使用ECharts将MySQL数据库中的数据可视化需要分步骤完成。以下是详细的实现流程:一、技术架构‌后端服务‌:使用PythonFlask框架搭建API(简单易学,适合新手)数据库连接‌:通过Python的pymysql库连接MySQL前端可视化‌:HTML+JavaScript+ECharts数据流向‌:MySQL数据库→Pyt</div>
                    </li>
                    <li><a href="/article/1903030101478535168.htm"
                           title="计算机毕业设计JavaBS景区票务管理系统设计与实现(源码+系统+mysql数据库+lw文档)" target="_blank">计算机毕业设计JavaBS景区票务管理系统设计与实现(源码+系统+mysql数据库+lw文档)</a>
                        <span class="text-muted">毅铭科技</span>
<a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E5%BA%93/1.htm">数据库</a>
                        <div>计算机毕业设计JavaBS景区票务管理系统设计与实现(源码+系统+mysql数据库+lw文档)计算机毕业设计JavaBS景区票务管理系统设计与实现(源码+系统+mysql数据库+lw文档)本源码技术栈:项目架构:B/S架构开发语言:Java语言开发软件:ideaeclipse前端技术:Layui、HTML、CSS、JS、JQuery等技术后端技术:JAVA运行环境:Win10、JDK1.8数据库:</div>
                    </li>
                    <li><a href="/article/1903025553070419968.htm"
                           title="金融、教育等行业如何高效利用wangEditor实现word文档网页化编辑?" target="_blank">金融、教育等行业如何高效利用wangEditor实现word文档网页化编辑?</a>
                        <span class="text-muted">2501_90699850</span>
<a class="tag" taget="_blank" href="/search/%E9%87%91%E8%9E%8D/1.htm">金融</a><a class="tag" taget="_blank" href="/search/word/1.htm">word</a><a class="tag" taget="_blank" href="/search/umeditor%E7%B2%98%E8%B4%B4word/1.htm">umeditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E7%B2%98%E8%B4%B4word/1.htm">ueditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E5%A4%8D%E5%88%B6word/1.htm">ueditor复制word</a><a class="tag" taget="_blank" href="/search/ueditor%E4%B8%8A%E4%BC%A0word%E5%9B%BE%E7%89%87/1.htm">ueditor上传word图片</a><a class="tag" taget="_blank" href="/search/ueditor%E5%AF%BC%E5%85%A5word/1.htm">ueditor导入word</a>
                        <div>要求:开源,免费,技术支持编辑器:wangEditor前端:vue2,vue3,vue-cli,html5后端:java,jsp,springboot,asp.net,php,asp,.netcore,.netmvc,.netform群体:学生,个人用户,外包,自由职业者,中小型网站,博客,场景:数字门户,数字中台,站群,内网,外网,信创国产化环境,web截屏行业:医疗,教育,建筑,政府,党政,国</div>
                    </li>
                    <li><a href="/article/1903025549899526144.htm"
                           title="网页编辑器能否满足Word公式与图片的直接复制粘贴?" target="_blank">网页编辑器能否满足Word公式与图片的直接复制粘贴?</a>
                        <span class="text-muted">2501_90699800</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E8%BE%91%E5%99%A8/1.htm">编辑器</a><a class="tag" taget="_blank" href="/search/word/1.htm">word</a><a class="tag" taget="_blank" href="/search/umeditor%E7%B2%98%E8%B4%B4word/1.htm">umeditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E7%B2%98%E8%B4%B4word/1.htm">ueditor粘贴word</a><a class="tag" taget="_blank" href="/search/ueditor%E5%A4%8D%E5%88%B6word/1.htm">ueditor复制word</a><a class="tag" taget="_blank" href="/search/ueditor%E4%B8%8A%E4%BC%A0word%E5%9B%BE%E7%89%87/1.htm">ueditor上传word图片</a><a class="tag" taget="_blank" href="/search/ueditor%E5%AF%BC%E5%85%A5word/1.htm">ueditor导入word</a>
                        <div>要求:开源,免费,技术支持编辑器:百度ueditor前端:vue2,vue3,vue-cli,react,html5用户体验:Ctrl+V快捷键操作功能:导入Word,导入Excel,导入PPT(PowerPoint),导入PDF,复制粘贴word,导入微信公众号内容,web截屏平台:Windows,macOS,Linux,RedHat,CentOS,Ubuntu,中标麒麟,银河麒麟,统信UOS,</div>
                    </li>
                    <li><a href="/article/1903019118886449152.htm"
                           title="高级前端面试题-React" target="_blank">高级前端面试题-React</a>
                        <span class="text-muted">圣诞小子</span>
<a class="tag" taget="_blank" href="/search/javascript/1.htm">javascript</a><a class="tag" taget="_blank" href="/search/%E9%9D%A2%E8%AF%95/1.htm">面试</a>
                        <div>react概念类组件和函数组件,什么时候用类组件获取组件实例类组件如何实现逻辑复用?高阶组件、renderprops选择hooks的优点状态逻辑复用;状态逻辑集中,易于理解;类组件不利于优化,比如不能很好的压缩为什么要用hooks,解决了什么问题同上react的context的使用场景共享对一个组件树全局的信息,不需要一层层传参受控组件和非受控组件非受控组件:数据只保存在内部state中;受控组件</div>
                    </li>
                    <li><a href="/article/1903017104097996800.htm"
                           title="GS-SLAM论文阅读笔记-MGSO" target="_blank">GS-SLAM论文阅读笔记-MGSO</a>
                        <span class="text-muted">zenpluck</span>
<a class="tag" taget="_blank" href="/search/GS%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB/1.htm">GS论文阅读</a><a class="tag" taget="_blank" href="/search/%E8%AE%BA%E6%96%87%E9%98%85%E8%AF%BB/1.htm">论文阅读</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0/1.htm">笔记</a>
                        <div>前言MGSO首字母缩略词是直接稀疏里程计(DSO),我们建立的光度SLAM系统和高斯飞溅(GS)的混合。这应该是第一个前端用DSO的高斯SLAM,不知道这个系统的组合能不能打得过ORB-SLAM3,以及对DSO会做出怎么样的改进以适应高斯地图,接下来就看一下吧!GishelloG^s_ihelloGishello我是红色文章目录前言1.背景介绍2.关键内容2.1SLAMmodule2.2Dense</div>
                    </li>
                                <li><a href="/article/57.htm"
                                       title="多线程编程之join()方法" target="_blank">多线程编程之join()方法</a>
                                    <span class="text-muted">周凡杨</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/JOIN/1.htm">JOIN</a><a class="tag" taget="_blank" href="/search/%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">多线程</a><a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/%E7%BA%BF%E7%A8%8B/1.htm">线程</a>
                                    <div>现实生活中,有些工作是需要团队中成员依次完成的,这就涉及到了一个顺序问题。现在有T1、T2、T3三个工人,如何保证T2在T1执行完后执行,T3在T2执行完后执行?问题分析:首先问题中有三个实体,T1、T2、T3, 因为是多线程编程,所以都要设计成线程类。关键是怎么保证线程能依次执行完呢?   
Java实现过程如下: 
public class T1 implements Runnabl</div>
                                </li>
                                <li><a href="/article/184.htm"
                                       title="java中switch的使用" target="_blank">java中switch的使用</a>
                                    <span class="text-muted">bingyingao</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/enum/1.htm">enum</a><a class="tag" taget="_blank" href="/search/break/1.htm">break</a><a class="tag" taget="_blank" href="/search/continue/1.htm">continue</a>
                                    <div>java中的switch仅支持case条件仅支持int、enum两种类型。 
用enum的时候,不能直接写下列形式。 
 
 
switch (timeType) {
            case ProdtransTimeTypeEnum.DAILY:

                break;

            default:
                br</div>
                                </li>
                                <li><a href="/article/311.htm"
                                       title="hive having count 不能去重" target="_blank">hive having count 不能去重</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/hive/1.htm">hive</a><a class="tag" taget="_blank" href="/search/%E5%8E%BB%E9%87%8D/1.htm">去重</a><a class="tag" taget="_blank" href="/search/having+count/1.htm">having count</a><a class="tag" taget="_blank" href="/search/%E8%AE%A1%E6%95%B0/1.htm">计数</a>
                                    <div>hive在使用having count()是,不支持去重计数 
  
hive (default)> select imei from t_test_phonenum where ds=20150701 group by imei having count(distinct phone_num)>1 limit 10;  
FAILED: SemanticExcep</div>
                                </li>
                                <li><a href="/article/438.htm"
                                       title="WebSphere对JSP的缓存" target="_blank">WebSphere对JSP的缓存</a>
                                    <span class="text-muted">周凡杨</span>
<a class="tag" taget="_blank" href="/search/WAS+JSP+%E7%BC%93%E5%AD%98/1.htm">WAS JSP 缓存</a>
                                    <div>      对于线网上的工程,更新JSP到WebSphere后,有时会出现修改的jsp没有起作用,特别是改变了某jsp的样式后,在页面中没看到效果,这主要就是由于websphere中缓存的缘故,这就要清除WebSphere中jsp缓存。要清除WebSphere中JSP的缓存,就要找到WAS安装后的根目录。 
       现服务</div>
                                </li>
                                <li><a href="/article/565.htm"
                                       title="设计模式总结" target="_blank">设计模式总结</a>
                                    <span class="text-muted">朱辉辉33</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/1.htm">设计模式</a>
                                    <div>1.工厂模式 
  1.1 工厂方法模式 (由一个工厂类管理构造方法) 
     1.1.1普通工厂模式(一个工厂类中只有一个方法) 
     1.1.2多工厂模式(一个工厂类中有多个方法) 
     1.1.3静态工厂模式(将工厂类中的方法变成静态方法) 
&n</div>
                                </li>
                                <li><a href="/article/692.htm"
                                       title="实例:供应商管理报表需求调研报告" target="_blank">实例:供应商管理报表需求调研报告</a>
                                    <span class="text-muted">老A不折腾</span>
<a class="tag" taget="_blank" href="/search/finereport/1.htm">finereport</a><a class="tag" taget="_blank" href="/search/%E6%8A%A5%E8%A1%A8%E7%B3%BB%E7%BB%9F/1.htm">报表系统</a><a class="tag" taget="_blank" href="/search/%E6%8A%A5%E8%A1%A8%E8%BD%AF%E4%BB%B6/1.htm">报表软件</a><a class="tag" taget="_blank" href="/search/%E4%BF%A1%E6%81%AF%E5%8C%96%E9%80%89%E5%9E%8B/1.htm">信息化选型</a>
                                    <div>引言 
随着企业集团的生产规模扩张,为支撑全球供应链管理,对于供应商的管理和采购过程的监控已经不局限于简单的交付以及价格的管理,目前采购及供应商管理各个环节的操作分别在不同的系统下进行,而各个数据源都独立存在,无法提供统一的数据支持;因此,为了实现对于数据分析以提供采购决策,建立报表体系成为必须。 业务目标 
1、通过报表为采购决策提供数据分析与支撑 
2、对供应商进行综合评估以及管理,合理管理和</div>
                                </li>
                                <li><a href="/article/819.htm"
                                       title="mysql" target="_blank">mysql</a>
                                    <span class="text-muted">林鹤霄</span>

                                    <div>转载源:http://blog.sina.com.cn/s/blog_4f925fc30100rx5l.html 
mysql -uroot -p 
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) 
  
[root@centos var]# service mysql</div>
                                </li>
                                <li><a href="/article/946.htm"
                                       title="Linux下多线程堆栈查看工具(pstree、ps、pstack)" target="_blank">Linux下多线程堆栈查看工具(pstree、ps、pstack)</a>
                                    <span class="text-muted">aigo</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a>
                                    <div>原文:http://blog.csdn.net/yfkiss/article/details/6729364 
  
1. pstree 
pstree以树结构显示进程$ pstree -p work | grep adsshd(22669)---bash(22670)---ad_preprocess(4551)-+-{ad_preprocess}(4552)  &n</div>
                                </li>
                                <li><a href="/article/1073.htm"
                                       title="html input与textarea 值改变事件" target="_blank">html input与textarea 值改变事件</a>
                                    <span class="text-muted">alxw4616</span>
<a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a>
                                    <div>// 文本输入框(input) 文本域(textarea)值改变事件 
// onpropertychange(IE) oninput(w3c) 
$('input,textarea').on('propertychange input', function(event) { 
     console.log($(this).val()) 
}); 
  </div>
                                </li>
                                <li><a href="/article/1200.htm"
                                       title="String类的基本用法" target="_blank">String类的基本用法</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/String/1.htm">String</a>
                                    <div>  
字符串的用法; 
    // 根据字节数组创建字符串 
byte[] by = { 'a', 'b', 'c', 'd' };
String newByteString = new String(by); 
  
  
    1,length()  获取字符串的长度 
  
  &nbs</div>
                                </li>
                                <li><a href="/article/1327.htm"
                                       title="JDK1.5 Semaphore实例" target="_blank">JDK1.5 Semaphore实例</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/thread/1.htm">thread</a><a class="tag" taget="_blank" href="/search/java%E5%A4%9A%E7%BA%BF%E7%A8%8B/1.htm">java多线程</a><a class="tag" taget="_blank" href="/search/Semaphore/1.htm">Semaphore</a>
                                    <div>Semaphore类 
       一个计数信号量。从概念上讲,信号量维护了一个许可集合。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。 
S</div>
                                </li>
                                <li><a href="/article/1454.htm"
                                       title="使用GZip来压缩传输量" target="_blank">使用GZip来压缩传输量</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/GZip/1.htm">GZip</a>
                                    <div>        启动GZip压缩要用到一个开源的Filter:PJL Compressing Filter。这个Filter自1.5.0开始该工程开始构建于JDK5.0,因此在JDK1.4环境下只能使用1.4.6。 
        PJL Compressi</div>
                                </li>
                                <li><a href="/article/1581.htm"
                                       title="【Java范型三】Java范型详解之范型类型通配符" target="_blank">【Java范型三】Java范型详解之范型类型通配符</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>  
  
定义如下一个简单的范型类, 
  
package com.tom.lang.generics;

public class Generics<T> {
    private T value;
    public Generics(T  value) {
        this.value = value;
    }
} </div>
                                </li>
                                <li><a href="/article/1708.htm"
                                       title="【Hadoop十二】HDFS常用命令" target="_blank">【Hadoop十二】HDFS常用命令</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/hadoop/1.htm">hadoop</a>
                                    <div>1. 修改日志文件查看器 
  
hdfs oev -i edits_0000000000000000081-0000000000000000089 -o edits.xml
cat edits.xml 
  
修改日志文件转储为xml格式的edits.xml文件,其中每条RECORD就是一个操作事务日志 
  2. fsimage查看HDFS中的块信息等 
&nb</div>
                                </li>
                                <li><a href="/article/1835.htm"
                                       title="怎样区别nginx中rewrite时break和last" target="_blank">怎样区别nginx中rewrite时break和last</a>
                                    <span class="text-muted">ronin47</span>

                                    <div>在使用nginx配置rewrite中经常会遇到有的地方用last并不能工作,换成break就可以,其中的原理是对于根目录的理解有所区别,按我的测试结果大致是这样的。  
 
 location /    
 {     
     proxy_pass http://test; </div>
                                </li>
                                <li><a href="/article/1962.htm"
                                       title="java-21.中兴面试题 输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 , 使其和等于 m" target="_blank">java-21.中兴面试题 输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 , 使其和等于 m</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class CombinationToSum {

	/*
第21 题
2010 年中兴面试题
编程求解:
输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数 ,
使其和等</div>
                                </li>
                                <li><a href="/article/2089.htm"
                                       title="eclipse svn 帐号密码修改问题" target="_blank">eclipse svn 帐号密码修改问题</a>
                                    <span class="text-muted">开窍的石头</span>
<a class="tag" taget="_blank" href="/search/eclipse/1.htm">eclipse</a><a class="tag" taget="_blank" href="/search/SVN/1.htm">SVN</a><a class="tag" taget="_blank" href="/search/svn%E5%B8%90%E5%8F%B7%E5%AF%86%E7%A0%81%E4%BF%AE%E6%94%B9/1.htm">svn帐号密码修改</a>
                                    <div>问题描述: 
     Eclipse的SVN插件Subclipse做得很好,在svn操作方面提供了很强大丰富的功能。但到目前为止,该插件对svn用户的概念极为淡薄,不但不能方便地切换用户,而且一旦用户的帐号、密码保存之后,就无法再变更了。 
解决思路: 
     删除subclipse记录的帐号、密码信息,重新输入</div>
                                </li>
                                <li><a href="/article/2216.htm"
                                       title="[电子商务]传统商务活动与互联网的结合" target="_blank">[电子商务]传统商务活动与互联网的结合</a>
                                    <span class="text-muted">comsci</span>
<a class="tag" taget="_blank" href="/search/%E7%94%B5%E5%AD%90%E5%95%86%E5%8A%A1/1.htm">电子商务</a>
                                    <div> 
 
      某一个传统名牌产品,过去销售的地点就在某些特定的地区和阶层,现在进入互联网之后,用户的数量群突然扩大了无数倍,但是,这种产品潜在的劣势也被放大了无数倍,这种销售利润与经营风险同步放大的效应,在最近几年将会频繁出现。。。。 
 
       如何避免销售量和利润率增加的</div>
                                </li>
                                <li><a href="/article/2343.htm"
                                       title="java 解析 properties-使用 Properties-可以指定配置文件路径" target="_blank">java 解析 properties-使用 Properties-可以指定配置文件路径</a>
                                    <span class="text-muted">cuityang</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/properties/1.htm">properties</a>
                                    <div>#mq 
xdr.mq.url=tcp://192.168.100.15:61618; 
 
import java.io.IOException; 
import java.util.Properties; 
 
 
public class Test { 
 
 String conf = "log4j.properties"; 
 private static final</div>
                                </li>
                                <li><a href="/article/2470.htm"
                                       title="Java核心问题集锦" target="_blank">Java核心问题集锦</a>
                                    <span class="text-muted">darrenzhu</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%9F%BA%E7%A1%80/1.htm">基础</a><a class="tag" taget="_blank" href="/search/%E6%A0%B8%E5%BF%83/1.htm">核心</a><a class="tag" taget="_blank" href="/search/%E9%9A%BE%E7%82%B9/1.htm">难点</a>
                                    <div>注意,这里的参考文章基本来自Effective Java和jdk源码 
 
 
1)ConcurrentModificationException 
当你用for each遍历一个list时,如果你在循环主体代码中修改list中的元素,将会得到这个Exception,解决的办法是: 
1)用listIterator, 它支持在遍历的过程中修改元素, 
2)不用listIterator, new一个</div>
                                </li>
                                <li><a href="/article/2724.htm"
                                       title="1分钟学会Markdown语法" target="_blank">1分钟学会Markdown语法</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/markdown/1.htm">markdown</a>
                                    <div>markdown 简明语法 基本符号 
 
 *,-,+ 3个符号效果都一样,这3个符号被称为 Markdown符号  
 空白行表示另起一个段落 
 `是表示inline代码,tab是用来标记 代码段,分别对应html的code,pre标签 
 换行 
 
 单一段落( <p>) 用一个空白行 
 连续两个空格 会变成一个 <br> 
 连续3个符号,然后是空行</div>
                                </li>
                                <li><a href="/article/2851.htm"
                                       title="Gson使用二(GsonBuilder)" target="_blank">Gson使用二(GsonBuilder)</a>
                                    <span class="text-muted">eksliang</span>
<a class="tag" taget="_blank" href="/search/json/1.htm">json</a><a class="tag" taget="_blank" href="/search/gson/1.htm">gson</a><a class="tag" taget="_blank" href="/search/GsonBuilder/1.htm">GsonBuilder</a>
                                    <div>转载请出自出处:http://eksliang.iteye.com/blog/2175473 一.概述 
    GsonBuilder用来定制java跟json之间的转换格式 
  二.基本使用 
实体测试类: 
温馨提示:默认情况下@Expose注解是不起作用的,除非你用GsonBuilder创建Gson的时候调用了GsonBuilder.excludeField</div>
                                </li>
                                <li><a href="/article/2978.htm"
                                       title="报ClassNotFoundException: Didn't find class "...Activity" on path: DexPathList" target="_blank">报ClassNotFoundException: Didn't find class "...Activity" on path: DexPathList</a>
                                    <span class="text-muted">gundumw100</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a>
                                    <div>有一个工程,本来运行是正常的,我想把它移植到另一台PC上,结果报: 
 
 java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.mobovip.bgr/com.mobovip.bgr.MainActivity}: java.lang.ClassNotFoundException: Didn't f</div>
                                </li>
                                <li><a href="/article/3105.htm"
                                       title="JavaWeb之JSP指令" target="_blank">JavaWeb之JSP指令</a>
                                    <span class="text-muted">ihuning</span>
<a class="tag" taget="_blank" href="/search/javaweb/1.htm">javaweb</a>
                                    <div>  
要点 
  
JSP指令简介  
page指令  
include指令  
  
JSP指令简介  
  
JSP指令(directive)是为JSP引擎而设计的,它们并不直接产生任何可见输出,而只是告诉引擎如何处理JSP页面中的其余部分。 
JSP指令的基本语法格式: 
<%@ 指令 属性名="</div>
                                </li>
                                <li><a href="/article/3232.htm"
                                       title="mac上编译FFmpeg跑ios" target="_blank">mac上编译FFmpeg跑ios</a>
                                    <span class="text-muted">啸笑天</span>
<a class="tag" taget="_blank" href="/search/ffmpeg/1.htm">ffmpeg</a>
                                    <div>1、下载文件:https://github.com/libav/gas-preprocessor, 复制gas-preprocessor.pl到/usr/local/bin/下, 修改文件权限:chmod 777 /usr/local/bin/gas-preprocessor.pl 
2、安装yasm-1.2.0 
curl http://www.tortall.net/projects/yasm</div>
                                </li>
                                <li><a href="/article/3359.htm"
                                       title="sql mysql oracle中字符串连接" target="_blank">sql mysql oracle中字符串连接</a>
                                    <span class="text-muted">macroli</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/sql/1.htm">sql</a><a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a><a class="tag" taget="_blank" href="/search/SQL+Server/1.htm">SQL Server</a>
                                    <div>有的时候,我们有需要将由不同栏位获得的资料串连在一起。每一种资料库都有提供方法来达到这个目的: 
 
 MySQL: CONCAT() 
 Oracle: CONCAT(), || 
 SQL Server: + 
 
CONCAT() 的语法如下: 
Mysql 中 CONCAT(字串1, 字串2, 字串3, ...): 将字串1、字串2、字串3,等字串连在一起。 
请注意,Oracle的CON</div>
                                </li>
                                <li><a href="/article/3486.htm"
                                       title="Git fatal: unab SSL certificate problem: unable to get local issuer ce rtificate" target="_blank">Git fatal: unab SSL certificate problem: unable to get local issuer ce rtificate</a>
                                    <span class="text-muted">qiaolevip</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0%E6%B0%B8%E6%97%A0%E6%AD%A2%E5%A2%83/1.htm">学习永无止境</a><a class="tag" taget="_blank" href="/search/%E6%AF%8F%E5%A4%A9%E8%BF%9B%E6%AD%A5%E4%B8%80%E7%82%B9%E7%82%B9/1.htm">每天进步一点点</a><a class="tag" taget="_blank" href="/search/git/1.htm">git</a><a class="tag" taget="_blank" href="/search/%E7%BA%B5%E8%A7%82%E5%8D%83%E8%B1%A1/1.htm">纵观千象</a>
                                    <div>// 报错如下: 
$ git pull origin master 
fatal: unable to access 'https://git.xxx.com/': SSL certificate problem: unable to get local issuer ce 
rtificate 
  
// 原因: 
由于git最新版默认使用ssl安全验证,但是我们是使用的git未设</div>
                                </li>
                                <li><a href="/article/3613.htm"
                                       title="windows命令行设置wifi" target="_blank">windows命令行设置wifi</a>
                                    <span class="text-muted">surfingll</span>
<a class="tag" taget="_blank" href="/search/windows/1.htm">windows</a><a class="tag" taget="_blank" href="/search/wifi/1.htm">wifi</a><a class="tag" taget="_blank" href="/search/%E7%AC%94%E8%AE%B0%E6%9C%ACwifi/1.htm">笔记本wifi</a>
                                    <div>还没有讨厌无线wifi的无尽广告么,还在耐心等待它慢慢启动么 
教你命令行设置 笔记本电脑wifi: 
 
1、开启wifi命令 
 

netsh wlan set hostednetwork mode=allow ssid=surf8 key=bb123456
netsh wlan start hostednetwork
pause
 
 其中pause是等待输入,可以去掉 
 
2、</div>
                                </li>
                                <li><a href="/article/3740.htm"
                                       title="Linux(Ubuntu)下安装sysv-rc-conf" target="_blank">Linux(Ubuntu)下安装sysv-rc-conf</a>
                                    <span class="text-muted">wmlJava</span>
<a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/ubuntu/1.htm">ubuntu</a><a class="tag" taget="_blank" href="/search/sysv-rc-conf/1.htm">sysv-rc-conf</a>
                                    <div>安装:sudo apt-get install sysv-rc-conf 使用:sudo sysv-rc-conf 
操作界面十分简洁,你可以用鼠标点击,也可以用键盘方向键定位,用空格键选择,用Ctrl+N翻下一页,用Ctrl+P翻上一页,用Q退出。 
  
  
背景知识 
sysv-rc-conf是一个强大的服务管理程序,群众的意见是sysv-rc-conf比chkconf</div>
                                </li>
                                <li><a href="/article/3867.htm"
                                       title="svn切换环境,重发布应用多了javaee标签前缀" target="_blank">svn切换环境,重发布应用多了javaee标签前缀</a>
                                    <span class="text-muted">zengshaotao</span>
<a class="tag" taget="_blank" href="/search/javaee/1.htm">javaee</a>
                                    <div>更换了开发环境,从杭州,改变到了上海。svn的地址肯定要切换的,切换之前需要将原svn自带的.svn文件信息删除,可手动删除,也可通过废弃原来的svn位置提示删除.svn时删除。 
  
然后就是按照最新的svn地址和规范建立相关的目录信息,再将原来的纯代码信息上传到新的环境。然后再重新检出,这样每次修改后就可以看到哪些文件被修改过,这对于增量发布的规范特别有用。 
  
检出</div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>