zoukankan      html  css  js  c++  java
  • BOM之定时器

    JavaScript中的时间是通过定时器控制的,他们分别是window.setInterval和window.setTimeout,我们当然可以省略window,直接使用方法名称调用。

    一  事件分类

      在讲解定时器之前,我们需要先明白 JavaScript 中事件(任务)的分类。

      JavaScript 把所有代码当做事件或任务来执行,由于 JavaScript 是单线程的,所以无论如何它都只能自上而下,一个一个的来执行任务,在做一件事时,不能干其他事,即同步。然而,随着时代的发展,异步的需求越来越多,浏览器(宿主环境)就为我们实现了异步执行任务的 API,本文即将要讲解的定时器就是典型的异步操作。

       ECMAScript 是同步执行的,浏览器又实现了异步API,那么 JavaScript 是怎么保证他们不冲突的呢?事件分类解决了这个问题。

      普通的 JavaScript 语句依然同步执行,但他们执行的地方在 JavaScript 主线程执行栈中,这些任务我们称作同步任务。

      异步API 任务则在单独的线程任务队列中执行,这些任务我们称为异步任务。

      这些任务在执行时保持主线程优先原则,即使异步任务满足不用等待立即执行的条件,也还是要等待同步任务执行完毕。

    二  setTimeout

      在等待指定的毫秒数后执行函数,语法如下:

      setTimeout(code/function, milliseconds, param1, param2, ...)

      方法接受2个或多个参数,第一个是一段JS代码或一个函数引用,第二个是需要等待的时间(以毫秒计),如果第一个参数是函数引用,并且需要传递参数,可以在后面依次传入。方法返回一个唯一id,代表该定时器,使用clearTimeout(id)可以清除定时器。

    1 setTimeout(functon(){
    2         console.log(new Date());
    3     },3000);
    4 console.log(new Date());
    5 //立即显示一次当前时间,3秒后又将显示一次

      经测试发现:如果第一个参数是一段JS代码而非函数引用,该代码将立即被执行,而不会延时等待。

    三    setInterval

      等同于 setTimeout(),但持续重复执行该函数。语法如下:

      setInterval(code/function, milliseconds, param1, param2, ...)

      使用方法和setTimeout()相同。

    1 function timer(){
    2     var d = new Date();
    3     document.body.innerText = d;
    4 }
    5 setInterval(timer,1000);

      上面是一个简单的定时器示例。

      另外,setInterval方法有一个严重的缺陷,那就是不能确保执行时间的准确性。

    在执行setInterval()时,假如我们设置每1s执行一次函数,但函数执行一次需要花费2s。浏览器会每隔1s就向一个事件队列中添加一个事件(即执行一次函数),当第一次执行完毕(3s之后了),这时队列中已经有2个事件正在排队了,于是浏览器立即执行第二个事件(等待队列中的第一个)。这样明显和我们本意每1s执行一次函数不符。所以在setInterval中,与其说第二个参数是延时时间,不如说是每个事件执行的最大间隔时间更为准确。因为当事件执行时间大于设置的间隔时间时,两个任务执行之间是没有间隔时间的。

      有些书上表示,到了设置的时间点,如果上一次的函数还没执行完,那么本次事件将不会被添加到事件队列中去,这次事件将被跳过,直到未来设置的某一时间点,前面的任务已经完成,才向队列中添加下一个事件。但浏览器实际上是按照第一种方式管理事件队列的,即到了时间不管前面的是否执行完毕,都插入一个进去,然后依次等待执行。(我用的Chrome  76.0.3869.100测试)

      setInterval主要应用在绘制动画效果上,鉴于它对时间的不准确性,要想获得完美的动画效果请使用CSS3的Animation实现。另外,如果确实需要使用,请务必把握好间隔时间的设置。下面是使用setInterval封装的一个运动函数:

     1 var timer;
     2 function startMove(obj,json,Fn){
     3     var key;
     4     clearInterval(timer);
     5     timer = setInterval(function(){
     6         for(var prop in json){//json是一个包含需要改变的属性和目标值的对象。
     7             var bridge;
     8             if(prop == 'opacity'){
     9                 bridge = getStyle(obj,prop)*100;//为了便于计算,先放大100倍
    10             }else{
    11                 bridge = parseInt(getStyle(obj,prop));
    12             }
    13             var speed = (json[prop] - bridge)/6;
    14             speed = speed > 0?Math.ceil(speed):Math.floor(speed);//这里为了获得更好的动画效果,动态设置了运动速度。你当然可以给一个常数作为运动速度
    15             if(prop == 'opacity'){
    16                 obj.style[prop] = (bridge + speed) / 100;
    17             }else{
    18                 obj.style[prop]= bridge + speed + 'px';
    19             }
    20             if(bridge != json[prop]){
    21                 key = false;
    22             }else{
    23                 key = true;
    24             }
    25             if(key){
    26                 clearInterval(timer);
    27                 if(Fn)Fn();//当目标运动完成,执行回调函数
    28             }
    29         }
    30     },30);
    31 }
    32     
    33 function getStyle(obj,prop){//获取css样式值
    34     if(obj.currentStyle){//IE
    35         return obj.currentStyle(prop);
    36     }else{//其他
    37         return getComputedStyle(obj,false)[prop];
    38     }
    39 }
  • 相关阅读:
    小喵的在线共享编辑器
    简易漫画网站搭建-漫画喵Server版
    爬虫-漫画喵的100行逆袭
    应用OpenMP的一个简单的设计模式
    基于Caffe的Large Margin Softmax Loss的实现(中)
    基于Caffe的Large Margin Softmax Loss的实现(上)
    Oracle GoldenGate OGG管理员手册
    Spark快速大数据分析之RDD基础
    Apache Spark大数据分析入门(一)
    一文教你看懂大数据的技术生态圈:Hadoop,hive,spark
  • 原文地址:https://www.cnblogs.com/ruhaoren/p/11410724.html
Copyright © 2011-2022 走看看