16 XMLHttpRequest机制 - 异步回调

Posted by CodingWithAlice on April 13, 2021

16 XMLHttpRequest机制 - 异步回调

XMLHttpRequest解决的问题

在 XMLHttpRequest 出现之前,如果服务器数据有更新,依然需要重新刷新整个页面

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

补充:同步回调VS异步回调

定义

同步回调:回调函数 callback 是 在主函数返回之前执行 的,举例如下;

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)

异步回调:回调函数 在主函数外部执行,举例如下;

let callback = function(){
    console.log('i am do homework')
}
function doWork(cb) {
    console.log('start do work')
    // 在 doWork 函数执行结束后,又延时了 1 秒再执行
    setTimeout(cb,1000)   
    console.log('end do work')
}
doWork(callback)

回调函数的调用栈

同步回调:在当前主函数的上下文中执行回调函数 异步回调:一般有两种方式

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

XMLHttpRequest 运作机制

流程图

image-20210413110259377

发起XHR的简易请求代码

function GetWebData(URL){
    // 1: 新建 XMLHttpRequest 请求对象
    let xhr = new XMLHttpRequest()
	// 2: 注册相关事件回调处理函数 
    xhr.onreadystatechange = function () {
        switch(xhr.readyState){
          case 0: // 请求未初始化
            break;
          case 1://OPENED
            break;
          case 2://HEADERS_RECEIVED
            break;
          case 3://LOADING  
            break;
          case 4://DONE
            if(this.status == 200||this.status == 304){
                console.log(this.responseText);
            }
            break;
        }
    }
    xhr.ontimeout = function(e) { console.log('ontimeout') }
    xhr.onerror = function(e) { console.log('onerror') }
 
	//3: 创建请求
    xhr.open('Get', URL, true);// 创建一个 Get 请求, true - 采用异步
 
     // 4: 配置参数
    xhr.timeout = 3000 // 设置 xhr 请求的超时时间
    xhr.responseType = "text" // 设置响应返回的数据格式
    xhr.setRequestHeader("X_TEST","time.geekbang")
 
	// 5: 发送请求
    xhr.send();
}

代码实现步骤

第一步:创建 XMLHttpRequest 对象

let xhr = new XMLHttpRequest():JS创建一个 XMLHttpRequest 对象xhr,用来执行实际的网络请求操作

第二步:为 xhr 对象注册回调函数

网络请求比较耗时,注册回调函数后,后台执行完成后调用回调函数来同步执行结果。

XMLHttpRequest回调函数类型:

  • ontimeout,用来监控超时请求,如果后台请求超时了,该函数会被调用;
  • onerror,用来监控出错信息,如果后台请求出错了,该函数会被调用;
  • onreadystatechange,用来监控后台请求过程中的状态,比如可以监控到 HTTP 头加载完成的消息、HTTP 响应体消息以及数据加载完成的消息等

第三步:配置基础的请求信息+参数

xhr.open('Get', URL, true); // 异步 通过 open 接口配置一些基础的请求信息,包括请求的地址、请求方法(是 get 还是 post)和请求方式(同步还是异步请求)

也可以通过 xhr 内部属性类配置一些其他可选的请求信息,具体可以看上述代码

第四步:发起请求

xhr.send();

如顶部流程图所示,渲染进程会将请求发送给网络进程,然后网络进程负责资源的下载,等网络进程接收到数据之后,就会 利用 IPC 来通知渲染进程

渲染进程接收到消息之后,会将 xhr 的回调函数封装成任务并添加到消息队列 中,等主线程循环系统执行到该任务的时候,就会根据相关的状态来调用对应的回调函数

XMLHttpRequest 使用中的“坑”

1、跨域问题

2、HTTPS 混合内容的问题:HTTPS 混合内容是 HTTPS 页面中包含了不符合 HTTPS 安全要求的内容,比如包含了 HTTP 资源,通过 HTTP 加载的图像、视频、样式表、脚本等,都属于混合内容