XMLHttpRequest是怎么实现的?

介绍

在XMLHttpRequest出现之前,如果服务器数据有更新,依然需要重新刷新整个⻚⾯。⽽ XMLHttpRequest提供了从Web服务器获取数据的能⼒,如果你想要更新某条数据,只需要通过 XMLHttpRequest请求服务器提供的接⼝,就可以获取到服务器的数据,然后再操作DOM来更新⻚⾯内容, 整个过程只需要更新⽹⻚的⼀部分就可以了,⽽不⽤像之前那样还得刷新整个⻚⾯,这样既有效率⼜不会打 扰到⽤⼾。


回调函数 VS 系统调⽤栈

将⼀个函数作为参数传递给另外⼀个函数,那作为参数的这个函数就是回调函数

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,同时将callback作为参数传递给了doWork() 函数,这时在函数doWork()中callback就是回调函数

⾯的回调⽅法有个特点,就是回调函数callback是在主函数doWork返回之前执⾏的,我们把这个回调过 程称为同步回调


let callback = function(){
console.log('i am do homework')
}

function doWork(cb) {
console.log('start do work')
setTimeout(cb,0)
console.log('end do work')
}

doWork(callback)

使⽤了setTimeout函数让callback在doWork函数执⾏结束后执行,这次callback并没有在主函数doWork内部被调⽤,我们把这种回调函数在主函数外部执⾏的过程称为异步 回调

异步回调是指回调函数在主函数之外执⾏,⼀般有两 种⽅式:

  • 第⼀种是把异步函数做成⼀个任务,添加到信息队列尾部;
  • 第⼀种是把异步函数做成⼀个任务,添加到信息队列尾部;

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对象。

let xhr = new XMLHttpRequest()

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

因为⽹络请求⽐较耗时,所以要注册回调函数,这样后台任务执⾏完成之后就会通过调⽤回调函数来告诉其 执⾏结果。

XMLHttpRequest的回调函数主要有下⾯⼏种:

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

第三步:配置基础的请求信息。

通过open接⼝配置⼀些基础的请求信 息,包括请求的地址、请求⽅法(是get还是post)和请求⽅式(同步还是异步请求)。

还可以通过xhr.responseType = "text"来配置服务器返回的格式

可以通过xhr.setRequestHeader来添加⾃⼰专⽤的请求头属性


第四步:发起请求。

⼀切准备就绪之后,就可以调⽤xhr.send来发起⽹络请求了


XMLHttpRequest注意点

1.跨域问题

不是同⼀个源的情况下就涉及到了跨域 (在A站点中去访问不同源的B站点的内容)。默认情况下,跨域请求是不被允许的


2.HTTPS混合内容的问题

HTTPS混合内容是HTTPS⻚⾯中包含了不符合 HTTPS安全要求的内容,⽐如包含了HTTP资源,通过HTTP加载的图像、视频、样式表、脚本等,都属于 混合内容。

如果HTTPS请求⻚⾯中使⽤混合内容,浏览器会针对HTTPS混合内容显⽰警告,⽤来向⽤⼾表明此 HTTPS⻚⾯包含不安全的资源。⽐如打开站点 https://www.iteye.com/groups ,可以通过控制台看到混合 内容的警告,参考下图: