BOM导读

bom,即为,Browser Oject Model 就浏览器对象模型,BOM提供了独立于文档内容而与浏览器窗口进行交互的对象,其核新对象是 window.

window对象是浏览器的顶级对象,在js中,它是全局对象,js定义在全局作用域下的变量和函数都会变成window对象的属性和方法。

例如: 在全局作用域下num=10;,其实会自动变成 window.num=10; window 通常被省略

window 常见事件

load 页面加载事件

我们前面写的js代码都是在我们要操作的元素之后的,原因就是,代码是从上往下加载,js写到前面的话,是获取不了后面的元素的。

学习了bom之后,我们可以把代码写在onlaod之内。 window.onload 是窗口页面加载事件,当文档内容完全加载(包括图像,脚本文件,css文件等)之后会触发该事件。

如何使用
  • 传统注册方式

    window.onload=function(){
                //
    }
    

    使用这种方法,load只能使用一次,写了多个只能以最后一个处理函数为准

  • addEventListener()函数

    window.addEventListener('load',function(){
    		//
    });
    

DOMContentLoaded 窗口加载事件

仅dom加载完成时(不包括css,图片等)触发。

这个DOMContentLoaded 会比 load事件 先触发。

resize 窗口大小被调整

只要窗口发生像素变化,那么就会产生这个效果。

那么如何获取窗口大小呢?

  • window.innerWidth 窗口的文档显示区宽
  • window.innerHeight窗口的文档显示区的宽度。
  • window.outerHeight属性设置或返回一个窗口的外部高度,包括所有界面元素(如工具栏/滚动条)。
  • window.outerWidth属性设置或返回窗口的外部宽度,包括所有的界面元素(如工具栏/滚动)。

定时器

window对象有两个定时器

  • setTimeout()
  • setInterval()

window.setTimeout()(window可以省略) 定时器

setTimeout(回调函数,[延迟毫秒数]);

这个方法时,执行到这一句的时候,会延后执行回调函数。

第二个参数默认值为0,就是立马执行。

setTimeout 不会阻碍后面的语句执行

虽然setTimeout会延迟{}语句执行,但是不会延迟后面的语句执行,仿佛和多线程一样。其实这个问题,后面就会说到,js的执行机制。

        alert('验证');
        setTimeout(function(){
            alert('我会延后2秒出现');
        },2000);
        alert('settimeout 后面的语句不会收到他的延迟影响');

验证

window.clearTimeout() 清除定时器

clearTimeout(定时器ID)

我们通常设置定时器的时候,需要给定时器起一个id

var timer= setTimeout(function(){
    alert('我要被干掉了');
},50000);
clearTimeout(timer);

setInterval() 循环定时器定时器

setInterval(回调函数,[延迟毫秒数])

这个就是一个循环执行器,每隔延迟毫秒数就会调用回调函数。

clearInterval() 清除循环定时器

clearInterval(定时器ID)用法和前面的clearTimeout(定时器ID)一致

倒计时效果的实现

练习一下 setInterval();

    <div class="timer">
        <span class="day">1</span>天
        <span class="hour">1</span>时
        <span class="minute">1</span>分
        <span class="scecond">1</span>秒
    </div>

JavaScript的实现

        var days = document.querySelector('.day');
        var hours=document.querySelector('.hour');
        var minutes = document.querySelector('.minute');
        var sceconds= document.querySelector('.scecond');
        function getRTime() {
            var nowTime = +new Date();
            var inputTime = +new Date('2021/04/25 00:00:00');
            var times = nowTime > inputTime ? (nowTime - inputTime) / 1000 : (inputTime - nowTime) / 1000;
            var day = parseInt(times / 60 / 60 / 24);
            var hour = parseInt(times / 60 / 60 % 24);
            var m = parseInt(times / 60 % 60);
            var s = parseInt(times % 60);
            day = day < 10 ? '0' + day : day;
            hour = hour < 10 ? '0' + hour : hour;
            m = m < 10 ? '0' + m : m;
            s = s < 10 ? '0' + s : s;
            days.innerHTML=day;
            hours.innerHTML=hour;
            minutes.innerHTML=m;
            sceconds.innerHTML=s;
        }
		window.onload=getRTime();//防止页面刷新有空白的效果;
        setInterval(getRTime, 1000);

js执行机制

同步和异步

js在最大特点时单线程的,没法多线程。但是H5标准提出web worker ,运行js建立类似多线程,但本质上还是单线程,于是js出现了同步执行环境和异步执行环境。

同步执行环境:串行执行任务,只有上一个任务执行完了才能执行下一任务

异步执行环境。:对于一些特殊任务,跳过等待,先处理后续的任务允许一个任务。

一般来说异步任务有下面三种类型

  1. 普通事件 ,click 、resize等,
  2. 资源加载 , load ,error
  3. 定时器,setInterval ,setTimeout

由于本质上还是单线程,所以产生了任务队列与事件循环,来协调主线程与异步模块之间的工作。

js 事件循环 event loop

js在执行这些任务的时候,有如下循序,

  1. 先一步一步的执行主线程任务,
  2. 遇到异步任务,先不直接执行交给 异步进程处理
  3. 异步进程 来判断,是否将相应的异步任务推入任务队列(异步队列);
  4. 等执行栈里的同步任务执行完了
  5. 查询任务队列,如果存在任务,则取出一个任务推入主线程处理(先进先出);
  6. 重复 1-5的步骤 ,这样的循环叫做 事件循环

image-20210129174242331

我们还是那一段代码说话吧。

        console.log(1);
        setTimeout(function () {
            console.log(3);
        }, 1000);
        document.onclick=function(){
            console.log('我点击了');
        }
        console.log(2);

首先,同步任务就有,

        console.log(1);
        setTimeout(fn, 1000);
        document.onclick=fn();
        console.log(2);

在处理 setTimeout 和 onclick 的时候 ,就会把他们交给 异步进程处理

在 1s之前,我们 的异步进程判断 console.log(3); 和 console.log('我点击了'); 没有到触发条件,所以不放到任务队列里面

最后 主线程上的任务都执行完了,他会看看任务队列有没有任务,发现没有就继续查询。

没到1s前,我们点击了,异步进程判断console.log('我点击了'); 该去任务队列里面了,那么任务队列就会多了个任务 console.log('我点击了'); ,由于主线程没有任务了,就会把任务队列里的任务推入到主线程里执行。

主线程有没有事情干了,有去看看 任务队列领任务了。

1s到了 那么异步进程也会把console.log(3);放入任务队列,后面的事情就和前面的一样了,不断循环。

努力成长的程序员