• JS 演变、单线程、异步任务


    一、JS 介绍与演变

    • JS 组成:ECMAScript标准、DOM、BOM

      • ECMAScript 是JS语法标准(核心)
      • DOM:文档对象模型(提供访问、操作页面内容的API)
      • BOM:浏览器对象模型(提供与浏览器交互的API)
    • JS是一门脚本语言、解析型语言、弱类型语言、动态类型语言。

      • 脚本语言:不用编译,一边解析一边执行
      • 解析型语言:遇到一行代码就解析一行代码
      • 弱类型语言( 声明变量都用var ),不受数据类型的约束
      • 动态类型的语言:对象没有属性 或 对象没有方法,只需要通过.的方式进行添加就有了
    • 历史演变:

      • 始于1995年,前身为LiveScript,由网景公司 布兰登.艾奇 开发,主要处理 以前由服务端负责的数据验证
      • 后更名为JavaScript,功能演变为:前后端数据交互、页面特效、服务端开发(nodeJS)
      • JS的很多语法,和Java、C#语法相似,和Java毫无关系
    • JS 作为一门脚本语言,其运行环境:web浏览器、Node、Adobe Flash

    • DOM详解

      • DOM应该理解为一个规范,定义了HTML和XML文档的逻辑结构和文档操作的编程接口
      • DOM实际上是以面向对象的方式描述对象模型,将文档建模为一个个对象,以树状的结构组织
      • 总结:DOM这个规范,提供了一些API,来操作 HTML/XML的中的DOM对象(标签),影响DOM对象的在浏览器中展现形式

    二、JS 单线程

    1. js 运行在浏览器中,是单线程的

    • 即 js 代码始终在一个线程上执行,这个线程就是 js 引擎线程。
    • 每个浏览器只有一个JS引擎线程
    • js 的一大特点: 单线程,只能在一个线程上运行,即:js只能同时执行一个任务,其他任务要执行,需要排队。
    • js 单线程并不代表 js 引擎只有一个线程;js 引擎有多个线程:一个主线程、其他后台配合主线程。
    • js引擎线程 和 UI线程互斥:因为js可以操作DOM;导致js执行时会影响页面的渲染
    • HTML5提出Web Worker标准,允许js脚本创建多个线程,但子线程完全受主线程的控制、且不能操作DOM元素。所以这并没有改变 js 单线程的本质

    2. 浏览器是多线程的:

    • JS引擎线程: 执行js (和UI线程互斥)
    • UI渲染线程: 渲染页面 (和js引擎线程互斥)
    • 浏览器事件触发线程: 用于控制交互,响应用户
    • http请求线程: 用于处理请求,ajax是委托给浏览器新开的一个 http 线程
    • EventLoop轮询的处理线程: 用于处理轮训消息队列

    3. 浏览器中的 js 任务

    • 执行js代码
    • 对用户的输入(如:鼠标点击、键盘输入)作出反应
    • 处理异步的网络请求

    三、JS引擎线程中 工作原理

    1. js主线程 ---> 由js引擎提供

    • js 的一个的线程:执行js任务

    2. js同步任务 ---> js引擎中,主线程上一个个排队执行的任务

    • 主线程上排队执行的任务(排队执行)

    3. js异步任务 ---> js引擎中

    • 异步任务起初不会进入主线程,而是被放到 任务队列/消息队列
    • 异步任务延迟执行:只有当主线程的任务全部执行完,js引擎将异步任务放到主线程执行栈中执行,事件循环
    • 异步任务执行顺序:定时器到时间的先执行,除此的按顺序执行。

    4. js任务队列 / 消息队列 ---> js引擎中,存放 异步任务

    • 解析异步操作后,相关的异步任务( 事件、回调函数),就会被放到 js任务队列中,等待被处理
    • 只有主线程中的任务全部执行完,任务队列中的异步任务才会被放到js主线程的执行栈中执行

    5. 事件循环 EventLoop

    • 主线程从”任务队列”中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)
    • JS 会创建一个 类似 while(true) 的循环,每执行一次循环体的过程叫 tick
    • tick 过程:查看任务队列中是都有待处理的事件,如果有:则取出,放到js主线程中执行
    • 由于js是运行在单线程上的,所有浏览器单独开启一个线程来处理事件消息的轮询,避免阻塞js的执行。

    四、异步任务 执行机制

    1. 异步任务是如何被执行的?

    • 1、js主线程上有一个执行栈(execution context stack),用于执行任务
    • 2、js主线程之外,还存在一个"任务队列"(task queue),用于存放 异步任务
    • 3、一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列":看看里面有哪些事件?对应哪些异步任务?于是异步任务结束等待状态,进入主线程执行栈,开始执行。
    • 4、主线程不断重复上面的第三步。
    • 总之:异步任务执行有时间延迟,总是等同步任务执行完才执行。

    2.常见的异步任务 ---> onclick 等事件的毁掉函数

    • 当事件触发时,回调函数会被立即添加到任务队列中
    • 由浏览器内核的 DOM Binding 模块处理

    3. 常见的异步任务 ---> setTimeout / setInterval 等计时器 ( 时间延迟 )

    • 当定时器时间到,就把该事件放到 任务队列中 等待处理
    • 由浏览器内核的 timer 模块进行延时处理

    4. 常见的异步任务 ---> ajax 请求

    • 在网络请求完成返回之后,将回调函数添加到任务队列中
    • 由浏览器内核的 network 模块处理

    五、异步编程

    1. 异步编程是有需求的

    • 除了 onclick等事件、setTimeout、ajax 这些天生有异步任务
    • 有些函数本身很耗时,其他函数依赖这个函数的执行结果,就有必要 手动进行异步编程了

    2. 异步编程解决方案 ---> 回调函数

    • 优点:简单,容易理解 和部署
    • 缺点:层层嵌套,不利于js代码阅读、维护
    function f1(callback){
      setTimeout(function () {
        // f1的任务代码
        callback();
       }, 1000);
     }
       
    f1(f2)
    

    3. 异步编程解决方案 ---> 事件监听(事件驱动模式)

    • 关键:任务的执行 不取决于 代码的顺序;而是取决于某个事件是否被出发
    • f1.trigger('done')表示,执行f1函数完成后,立即触发done事件(从而执行f2)
      • 优点:比较容易理解,去耦合
      • 缺点:整个程序都要变成事件驱动型,运行流程变得不清晰
    // 这里采用的jQuery的写法
    
    f1.on('done', f2);
    
    function f1(){
      setTimeout(function () {
        // f1的任务代码
        f1.trigger('done');
      }, 1000);
    }
    

    4. 异步编程解决方案 ---> 发布 / 订阅 (观察者模式)

    • f1运行结束之后,像“消息中心”发出done信号,因f2之前向“消息中心”订阅了done信号,所以,此时f2开始执行。
    • 优点:这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
    jQuery.subscribe("done", f2);
    
    function f1(){
      setTimeout(function () {
        // f1的任务代码
        jQuery.publish("done");
      }, 1000);
    }
    

    5. 异步编程解决方案 ---> ES6中 Promises对象

    • Promises对象是CommonJS提出的一种规范,目的是为异步编程提供统一接口。
    • 每一个异步任务:都返回一个Promise对象
    • 优点:回调函数变成了链式写法,程序的流程可以看得很清楚;如果一个任务已经完成,再添加回调函数,该回调函数会立即执行。所以,你不用担心是否错过了某个事件或信号。
    function f1(){
      var dfd = $.Deferred();
      setTimeout(function () {
        // f1的任务代码
        dfd.resolve();
      }, 500);
      return dfd.promise;
    }
      
    f1().then(f2).then(f3);
    //指定失败的回调函数
    f1().then(f2).fail(f3);
    

    6. 异步编程解决方案 ---> ES7 引入了像C#语言中的 await,async关键字

    • async 定义函数;await 调用函数
    // 这里认为 f2 是异步函数
    
    async function f1 () {
        console.log(1);
        await f2();
        console.log(2);
    }
    
    // 以上执行顺序是: console.log(1); f2(); console.log(2);
    
  • 相关阅读:
    跨域
    关于DEDECMS自定义模型当中添加自定义字段后在后台添加内容后不显示解决方案
    js复制文本
    dedecms 织梦显示时间格式
    基本特效:饿了么丝滑无缝过度搜索栏的实现
    2016-wing的年度总结
    这交互炸了(四) :一分钟让你拥有微信拖拽透明返回PhotoView
    这交互炸了(三):闪屏页是像云一样消失的
    这交互炸了(二):爱范儿是如何让详情页缩小为横向列表的
    这交互炸了:饿了么是怎么让Image变成详情页的
  • 原文地址:https://www.cnblogs.com/zxvictory/p/8001176.html
Copyright © 2020-2023  润新知