JavaScript 层级优化

278 阅读3分钟

JavaScript的运行机制

  • 1.什么是线程

线程是操作系统能够进行运算调度的最小单位,被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务

  • 2.JavaScript执行机制与其他执行机制的异同

JavaScript作为一门浏览器脚本语言,当初研发之时就是为用户操作和浏览器DOM服务的,而多线程存在线程之间资源抢占,死锁,冲突等一系列问题。这就决定了JavaScript一定是单线程的,不然就存在着冲突问题。 因此所有浏览器的JS引擎(浏览器用于读取并执行JavaScript)在执行JavaScript只分配一个线程。虽然单线程不存在冲突的问题,但它同时也带来了一个新的问题--阻塞

console.log(1)

setTimeout(function(){
    console.log(2)
},0)

new Promise(function(resolve){
    resolve()
}).then(function(){
    console.log(3)
})

console.log(4)

定时器是一把双刃剑

定时器:用于在特定的时间执行特定的代码块,常见的定时器setTiemout、setInterval 、setImmediate、requestAnimationFrame。

  • 1.用好定时器
    • setTiemout(超时调用,只执行一次) 
    • setInterval(间隔调用,如果不做处理会一直执行)
    • setImmediate(在浏览器完全结束当前运行的操作之后立即执行指定的函数(仅IE10和Node 0.10+中有实现),类似setTimeout(func, 0))
    • requestAnimationFrame(专门为实现高性能的帧动画而设计的API,但是不能指定延迟时间,而是根据浏览器的刷新频率而定(帧))
  • 2.如何及时清除定时器
    • window.clearInterval
  • 3.合理使用css3动画
    • 如果能使用css3实现的动画,尽量不要用定时器去实现

定时器的使用----防抖函数

const debounce = (func, delay = 200) => {
  let timeout = null
  return function () {
    clearTimeout(timeout)
    timeout = setTimeout(() => {
      func.apply(this, arguments)
    }, delay)
  }
}

事件的绑定

  • 1.多利用事件代理委托
    • <input onclick="alert('自行车')" type="button" value="" />
    • <input onclick="myAlert()" type="button" value="" />
    • 代码中绑定

<script type="text/javascript">
  function myAlert(){
  alert("自行车");
  </script>

  <input id="demo" type="button" value="" />
  <script type="text/javascript">
  document.getElementById("demo").onclick=function(){
  alert(this.getAttribute("type")); // this 指当前发生事件的HTML元素,这里是<div>标签
  }
  • 2.避免重复的事件监听

事件委托


<ul id="ul1">
    <li>111</li>
    <li>222</li>
    <li>333</li>
    <li>444</li>
</ul>

window.onload = function(){
    var oUl = document.getElementById("ul1");
    var aLi = oUl.getElementsByTagName('li');
    for(var i=0;i<aLi.length;i++){
        aLi[i].onclick = function(){
            alert(123);
        }
    }
}

//事件 委托
window.onload = function(){
  var oUl = document.getElementById("ul1");
  oUl.onclick = function(ev){
    var ev = ev || window.event;
    var target = ev.target || ev.srcElement;
    if(target.nodeName.toLowerCase() == 'li'){
         alert(123);
         alert(target.innerHTML);
    }
  }
}


  • 3.事件捕获和事件冒泡

事件捕获和事件冒泡是啥?

  事件捕获和事件冒泡分别是Netscape和IE对DOM事件产生顺序的描述。Netscape认为DOM接收的事件最先应该是window接收,然后再一节一节往下,最后才是具体的元素接收到事件,即:事件捕获。而IE则认为DOM事件应该由具体元素最先接收事件,然后再一节一节往上,最后再由window接收事件,即:事件冒泡。最后W3C将两种方案做了统一,即:把DOM事件分为两个阶段,事件捕获阶段和事件冒泡阶段,例如:当页面某一个元素被点击,首先是事件捕获阶段,window最先接收事件,然后一节一节往下捕获,最后由具体元素接收,然后再由具体元素一节一节往上,最后window会再次接收事件,以下为DOM事件流示意图

一些优秀的javascript层级思想

  • 1.jquery的ready与原生的wondow.onload
  • 2.mvvm框架的组件生命周期
  • 3.变量缓存与私有化

使用hash对象,将数组的查询变得更简单

// 将a 数组和 B数组进行合并
let array = [{
    id: 1,
    name: '123123123'
},{
    id: 2,
    name: '123123123'
},{
    id: 3,
    name: '123123123'
},{
    id: 4,
    name: '123123123'
},{
    id: 5,
    name: '123123123'
}]
let b = [{
    id: 1,
    age: 19
},{
    id: 2,
    age: 19
},{
    id: 3,
    age: 19
},{
    id: 4,
    age: 19
},{
    id: 5,
    age: 19
}]


// 将 a数组和b数组进行合并, 如果我们不转化的智能通过循环遍历 n2
array.forEach(p => {
    b.find(j => {

    })
})

//如果转化成hash对象,,这复杂度编程n
let c = {} 
b.forEach(p => {
    c[p.id] = p
})

array.forEach(p => {
    p.age = c[p.id].age
})