5.XMLHttpRequest

  • 在 XMLHttpRequest 出现之前,如果服务器数据有更新,依然需要重新刷新整个页面。而 XMLHttpRequest 提供了从 Web 服务器获取数据的能力,如果你想要更新某条数据,只需要通过 XMLHttpRequest 请求服务器提供的接口,就可以获取到服务器的数据,然后再操作 DOM 来更新页面内容,整个过程只需要更新网页的一部分就可以了,而不用像之前那样还得刷新整个页面,这样既有效率又不会打扰到用户

  • 同步回调

    • 回调函数
    • Callback Function
    • 将一个函数作为参数传递给另外一个函数,那作为参数的这个函数就是回调函数。

let callback = function(){
    console.log('i am do homework')
}
function doWork(cb) {
    console.log('start do work')
    cb()
    console.log('end do work')
}
doWork(callback)
  • 回调函数 callback 是在主函数 doWork 返回之前执行的,我们把这个回调过程称为同步回调。
  • 异步回调

let callback = function(){
    console.log('i am do homework')
}
function doWork(cb) {
    console.log('start do work')
    setTimeout(cb,1000)   
    console.log('end do work')
}
doWork(callback)
  • callback 并没有在主函数 doWork 内部被调用,我们把这种回调函数在主函数外部执行的过程称为异步回调
  • 当循环系统在执行一个任务的时候,都要为这个任务维护一个系统调用栈。这个系统调用栈类似于 JavaScript 的调用栈.

  • 每个任务在执行过程中都有自己的调用栈,那么同步回调就是在当前主函数的上下文中执行回调函数.

  • 异步回调执行过程:

    • 第一种是把异步函数做成一个任务,添加到信息队列尾部;
    • 第二种是把异步函数添加到微任务队列中,这样就可以在当前任务的末尾处执行微任务了。
  • XMLHttpRequest 运作机制
    XMLHttpRequest 运作机制


 function GetWebData(URL){
    /**
     * 1:新建XMLHttpRequest请求对象
     */
    let xhr = new XMLHttpRequest()

    /**
     * 2:注册相关事件回调处理函数 
     */
    xhr.onreadystatechange = function () {
        switch(xhr.readyState){
          case 0: //请求未初始化
            console.log("请求未初始化")
            break;
          case 1://OPENED
            console.log("OPENED")
            break;
          case 2://HEADERS_RECEIVED
            console.log("HEADERS_RECEIVED")
            break;
          case 3://LOADING  
            console.log("LOADING")
            break;
          case 4://DONE
            if(this.status == 200||this.status == 304){
                console.log(this.responseText);
                }
            console.log("DONE")
            break;
        }
    }

    xhr.ontimeout = function(e) { console.log('ontimeout') }
    xhr.onerror = function(e) { console.log('onerror') }

    /**
     * 3:打开请求
     */
    xhr.open('Get', URL, true);//创建一个Get请求,采用异步


    /**
     * 4:配置参数
     */
    xhr.timeout = 3000 //设置xhr请求的超时时间
    xhr.responseType = "text" //设置响应返回的数据格式
    xhr.setRequestHeader("X_TEST","time.geekbang")

    /**
     * 5:发送请求
     */
    xhr.send();
}
  • 上面是利用了 XMLHttpRequest 来请求数据的代码
  • 结合流程图 分析代码执行流程:
  • 第一步:创建 XMLHttpRequest 对象。
    • 对象 xhr,用来执行实际的网络请求操作
  • 第二步:为 xhr 对象注册回调函数。
    • 网络请求比较耗时,所以要注册回调函数,这样后台任务执行完成之后就会通过调用回调函数来告诉其执行结果。
    • XMLHttpRequest 的回调函数主要有下面几种:
      • ontimeout,用来监控超时请求,如果后台请求超时了,该函数会被调用;
      • onerror,用来监控出错信息,如果后台请求出错了,该函数会被调用;
      • onreadystatechange,用来监控后台请求过程中的状态,比如可以监控到 HTTP 头加载完成的消息、HTTP 响应体消息以及数据加载完成的消息等。
  • 第三步:配置基础的请求信息。
    • 通过 open 接口配置一些基础的请求信息,包括请求的地址、请求方法(是 get 还是 post)和请求方式(同步还是异步请求)。
    • 通过 xhr 内部属性类配置一些其他可选的请求信息
      • xhr.timeout = 3000来配置超时时间。如果请求超过 3000 毫秒还没有响应,那么这次请求就被判断为失败了。
      • xhr.responseType = "text"来配置服务器返回的格式。将服务器返回的数据自动转换为自己想要的格式,如果将 responseType 的值设置为 json,那么系统会自动将服务器返回的数据转换为 JavaScript 对象格式。
        数据返回类型描述
      • 需要添加自己专用的请求头属性,可以通过 xhr.setRequestHeader 来添加。
  • 第四步:发起请求。
    • 调用xhr.send来发起网络请求
    • 渲染进程会将请求发送给网络进程,然后网络进程负责资源的下载,等网络进程接收到数据之后,就会利用 IPC 来通知渲染进程;渲染进程接收到消息之后,会将 xhr 的回调函数封装成任务并添加到消息队列中,等主线程循环系统执行到该任务的时候,就会根据相关的状态来调用对应的回调函数
    • 如果网络请求出错了,就会执行 xhr.onerror;
    • 如果超时了,就会执行 xhr.ontimeout;
    • 如果是正常的数据接收,就会执行 onreadystatechange 来反馈相应的状态。
    • 这就是一个完整的 XMLHttpRequest 请求流程。
  • XMLHttpRequest 使用过程中的“坑”

    • 跨域问题和混合内容问题:
      1. 跨域问题
      • 非同源
      1. HTTPS 混合内容的问题
      • HTTPS 页面中包含了不符合 HTTPS 安全要求的内容,比如包含了 HTTP 资源,通过 HTTP 加载的图像、视频、样式表、脚本等,都属于混合内容。
      • 通常,如果 HTTPS 请求页面中使用混合内容,浏览器会针对 HTTPS 混合内容显示警告,用来向用户表明此 HTTPS 页面包含不安全的资源。
      • 而使用 XMLHttpRequest 请求时,浏览器认为这种请求可能是攻击者发起的,会阻止此类危险的请求。
  • 对比上一篇文章,setTimeout 是直接将延迟任务添加到延迟队列中,而 XMLHttpRequest 发起请求,是由浏览器的其他进程或者线程去执行,然后再将执行结果利用 IPC 的方式通知渲染进程,之后渲染进程再将对应的消息添加到消息队列中。如果搞懂了 setTimeout 和 XMLHttpRequest 的工作机制后,再来理解其他 WebAPI 就会轻松很多了,因为大部分 WebAPI 的工作逻辑都是类似的。

笔记内容来自极客时间李兵老师的《浏览器工作原理与实践》 学习收获了很多 感谢老师

原文地址:https://www.cnblogs.com/liyf-98/p/14416048.html