面试必问之AJAX

723 阅读5分钟

预习:阮一峰 AJAX

本节要点:

  1. AJAX基础
  2. 深入AJAX

如何发请求?

用 form 可以发请求,但是会刷新页面或新开页面
用 a 可以发 get 请求,但是也会刷新页面或新开页面
用 img 可以发 get 请求,但是只能以图片的形式展示
用 link 可以发 get 请求,但是只能以 CSS、favicon 的形式展示
用 script 可以发 get 请求,但是只能以脚本的形式运行

有没有什么方式可以实现

  1. get、post、put、delete 请求都行
  2. 想以什么形式展示就以什么形式展示

AJAX

Jesse James Garrett 将如下三种技术共同使用取名叫做 AJAX:异步的 JavaScript 和 XML

  1. 使用 XMLHttpRequest 发请求
  2. 服务器返回 XML 格式的字符串
  3. JS 解析 XML,并更新局部页面

备注:后来用JSON语言代替了XML


如何使用 XMLHttpRequest

myButton.addEventListener('click', (e)=>{
  let request = new XMLHttpRequest() //产生这个对象
  request.open('get', '/xxx') // 配置request
  request.send() // 发送这个对象
  request.onreadystatechange = ()=>{  // 监听这个对象的各种状态
    if(request.readyState === 4){
      console.log('请求响应都完毕了')
      console.log(request.status)
      if(request.status >= 200 && request.status < 300){
        console.log('说明请求成功')
        console.log(typeof request.responseText)
        console.log(request.responseText)
        let string = request.responseText
        // 把符合 JSON 语法的字符串
        // 转换成 JS 对应的值
        let object = window.JSON.parse(string) 
        // JSON.parse 是浏览器提供的
        console.log(typeof object)
        console.log(object)
        console.log('object.note')
        console.log(object.note)

      }else if(request.status >= 400){
        console.log('说明请求失败') 
      }

    }
  }
})

// 后端代码
  }else if(path==='/xxx'){
    response.statusCode = 200
    response.setHeader('Content-Type', 'text/json;charset=utf-8')
    response.setHeader('Access-Control-Allow-Origin', 'http://frank.com:8001')
    response.write(`
    {
      "note":{
        "to": "小谷",
        "from": "方方",
        "heading": "打招呼",
        "content": "hi"
      }
    }
    `)
    response.end()

request.onreadystatechange === 4 表示请求完成


JSON是一门新语言

JSON只支持一部分的JS一部分语法,因为它抄袭了JS。

JS VS JSON

js               json
null             null
['a','b']        ["a","b"]
{name: 'om'}     {"name":"om"}
'om'             "om"
undefined        没有
function fn(){}  没有

var a={}
a.self = a       做不到
复杂对象         只有hash,没有原型链
  1. JSON没有抄袭 undefined 和 function
  2. JSON的字符串首尾必须是双引号""

同源策略

只有 协议+端口+域名 一模一样才允许发 AJAX 请求

一模一样一模一样一模一样一模一样一模一样一模一样一模一样一模一样

  1. baidu.com 可以向 www.baidu.com 发 AJAX 请求吗 no
  2. baidu.com:80 可以向 baidu.com:81 发 AJAX 请求吗 no

浏览器必须保证
只有 协议+端口+域名 一模一样才允许发 AJAX 请求
CORS 可以告诉浏览器,我俩一家的,别阻止他即CORS 跨域

  • 比如A允许B访问:
    A后台:response.setHeader('Access-Control-Allow-Origin','B的网址')
  • JSONP也可以,但是只能GET,最新的都是用CORS,不过也要结合前端和后台的水平,实际上两者都有。

突破同源策略 === 跨域

CORS:Cross-Origin Resource Sharing 跨站资源共享


小总结:

  1. 什么是AJAX?
    用JS发请求,用JS处理响应。
  2. 哪里用到了JSON?
    把XML替换为JSON。
  3. 什么是同源策略?
    只有协议端口域名一模一样才允许发AJAX请求。
  4. 如何突破同源策略即跨域?
    只需要在被访问的网站后台加一句话:
    response.setHeader('Access-Control-Allow-Origin','允许访问本网站的网页网址')

面试题:手写AJAX

就写出以下8行代码:(必背)

let request = new XMLHttpRequest()    //产生这个对象
  request.open('get', '/xxx')         // 配置request
  request.send()                      // 发送这个对象
  request.onreadystatechange = ()=>{  // 监听这个对象的各种状态
    if(request.readyState === 4){
      if(request.status >= 200 && request.status < 300){
        let string = request.responseText
        let object = window.JSON.parse(string)
      }
    }
  }

面试题:请使用原生JS发送AJAX请求

待填充,自行搜索也可。

深入AJAX

  1. JS 可以设置任意请求 header 吗?
    第一部分 request.open('get', '/xxx')
    第二部分 request.setRequestHeader('content-type','x-www-form-urlencoded')
    第四部分 request.send('a=1&b=2')
    i. XMLHttpRequest.setRequestHeader()是设置HTTP请求头部的方法。(第一部分,第二部分)
    ii. XMLHttpRequest.send()设置第四部分。

  2. JS 可以获取任意响应 header 吗?
    第一部分 request.status / request.statusText
    第二部分 request.getResponseHeader() / request.getAllResponseHeaders()
    第四部分 request.responseText
    i. XMLHttpRequest.status 是返回服务器回应的 HTTP 状态码。
       XMLHttpRequest.statusText 是返回表示服务器发送的状态提示的字符串。(第一部分) ii. XMLHttpRequest.getResponseHeader('')返回包含特定标头值的文本的字符串     XMLHttpRequest.getAllResponseHeaders()返回包含整个原始头的字符串。 (第二部分)
    iii. XMLHttpRequest.responseText()属性返回从服务器接收到的字符串(第四部分)

所以通过AJAX,我们可以任意设置请求中四个部分的任意内容(只是有些设置不接受),也可以获取响应中四个部分的任意内容。

如果你对下图的每一个字都懂了,那你对http请求有了完整的了解。

小技巧:

  1. JS中要传递给多个参数就把他们变成一个对象去传递。
let obj = {
    url: '/xxx',
    type: 'post',
    data: 'a=1&b=2'
    fn1: ()=>{},
    fn2: ()=>{},
}
$.ajax(obj)
  1. “1技巧”再简化不给那个对象命名,直接传递。这是最简方法。

$.ajax({
    url: '/xxx',
    type: 'post',
    data: 'a=1&b=2'
    fn1: ()=>{},
    fn2: ()=>{},
})
  1. ES6之析构赋值
ES5:
    let type: options.type
    let data: options.data
    let fn1: options.fn1
    let fn2: options.fn2
ES6:(以后都用这个)
    let {type,data,fn1.fn2} = options
  1. “结合方法2、3”,我们给ajax传递参数可以直接传递:
$.ajax({url, type, data, fn1, fn2})

到了这里,jQuery.AJAX已经全部理解了,现在直接去看jQuery.ajax文档


回调

  1. 什么是回调?(我也不懂,以后懂了再回来填坑)
call a function
call a function back

callback
先粗暴的理解 回调就是函数!
  1. 回调的问题
    问题是每个程序员的回调名不一样

Promise规范:(必须背会)

function xxx(){
    return new Promise((f1, f2) => {
        doSomething()
        setTimeout(()=>{
            // 成功就调用 f1,失败就调用 f2
        },3000)
    })
}

xxx().then(success, fail)

// 链式操作
xxx().then(success, fail).then(success, fail)
  1. 完全不用在意参数名字是什么,直接then( ,)就可以了。
  2. 可以使用多次them对同一个状态多次处理

如果要自己写Promise呢?

window.jQuery.ajax = function({url, type, data}){
    return new Promise(function(resole, reject){
        ···
    })
}
window.jQuery.ajax是我们自己写的ajax
Promise 就是 window.Promise
如果成功就调用resole,如果失败就调用reject


myButton.addEventListener('click', (e)=>{
  let promise = window..jQuery.ajax({
    url: '/xxx',
    type: 'post',
    data: 'a=1&b=2'
  })
  
  promise.then(
    (text) => {console.log(text)},
    (request) => {console.log(request)}
  )
})

Promise描述:
如果你要promise,就return一个promise对象,所以ajax必须return new promise对象;成功调resole,失败调reject;这个promise有一个then的api,then接受两个函数,如果上一动作成功就调第一个函数,如果上一动作失败就调第二个函数。

必须背会:

return new Promise(function(resole, reject){ })