详细的fetch发送请求,axios发送请求,底层Promise原理,async/await语法糖的使用

215 阅读5分钟

image.png

Ajax

英文全称为 Asynchronous JavaScript + XML ,翻译过来就是 异步JavaScript和XML

Ajax 最重要的特性就是可以局部刷新页面。

  • Ajax 是一种代表异步 JavaScript + XML 的模型(技术合集),所以 Fetch 也是 Ajax 的一个子集

  • 在之前,我们常说的 Ajax 默认是指以 XHR 为核心的技术合集,而在有了 Fetch 之后,Ajax 不再单单指 XHR 了,我们将以 XHR 为核心的 Ajax 技术称作传统 Ajax

  • Axios 属于传统 Ajax(XHR)的子集,因为它是基于 XHR 进行的封装。

xhr

xhr是利用 XMLHttpRequest 模块实现的最传统的网络请求

实现步骤:

  1. 创建xhr实例 const xhr = new XMLHttpRequest()
  2. 设置请求方法和地址 xhr.open(‘GET’, url)
  3. 如果是POST请求 ,告诉后端发送的参数是什么形式的xhr.setRequestHeader(‘content-type’,’application/json’)
  4. 发送请求 xhr.send()
  5. 注册回调
const xhr = new XMLHttpRequest() 
xhr.open('POST',url) 
xhr.setRequestHeader('content-type','application/x-www-form-  urlencoded') 
xhr.send(params) 
xhr.responseType = 'json' xhr.addEventListener('readystatechange',()=>{     if(xhr.readyState !==4) return     
    if(xhr.status >= 200 && xhr.status <300){ 
        console.log(xhr.response)     
}else{         
        console.log('错误')     
}

readyState ==> 请求状态码 , xhr的状态

  • 0 表示请求未初始化,还没有调用 open()
  • 1 表示服务器已建立 但是还没有 调用send()
  • 2 请求已接收, 正在处理中
  • 3 请求处理中 已经有部分数据响应了,没有全部完成
  • 4 请求已完成 (全部数据已经下载完了)

Axios

Axios 是一个基于 promise 封装的网络请求库,基于 XHR 进行二次封装形成的工具库,在项目中直接安装使用

Axios 是一个基于 Promise 网络请求库,作用于 Node.js 和浏览器中。在服务端它使用原生 Node.js http 模块,而在客户端则使用 XMLHttpRequest。

axions({
    method:"POST",
    data:{}, // 直接绑定 data (fetch 需要转换格式绑定在 body 上)
    params: {}, // params 会绑定在 url 查询上
    headers:{
        "content-type":"application/json" // headers 与 fetch ⼀致,但是默认值是 “application/json”
    }
}).then(res=>{
    // res.data 返回结果,res.status 返回状态
    // 没有第⼆段 then
    })
//get请求
axios({url})
.then(res => console.log(res))

//post
axios({
    method:"POST",
    data:{},
    params: {加载地址后面的},
    headers:{"content-type":"application/json" }
}).then(res => console.log(res.data))

fetch

口诀:fetch 两段 then,错误全 catch

Fetch 是一个现代的概念, 等同于 XMLHttpRequest。它提供了许多与 XMLHttpRequest 相同的功能,但被设计成更具可扩展性和高效性

Fetch 的核心在于对 HTTP 接口的抽象,包括 Request、Response、Headers 和 Body,以及用于初始化异步请求的 global fetch。得益于 JavaScript 实现的这些抽象好的 HTTP 模块,其他接口能够很方便的使用这些功能。

Fetch 还利用到了请求的异步特性——它是基于 Promise 的。

fetch() 方法必须接受一个参数——资源的路径。无论请求成功与否,它都返回一个 Promise 对象


fetch(url,{             
        method:"post",             
        headers:{'content-type':"application/json"},
        body:JSON.stringify(params)         
        }).then(res => res.json())         
          .then(res => console.log(res))         
          .catch(err => console.log(err)) 
          
//get请求        
fetch('http://ajax-api.itheima.net/api/news')         
    .then(res => res.json())         
    .then(res => console.log(res))         
    .catch(err => console.log(err)) 
//post请求 
    fetch('http://ajax-api.itheima.net/api/login',{    
        method:"post",             
        headers:{'content-type':"application/json"},  
        body:JSON.stringify(params)         
    }).then(res => res.json())         
    .then(res => console.log(res))         
    .catch(err => console.log(err))

promise

上面请求都是基于promise,因为请求都是异步运行的,所以promise是用来做异步处理的,下面来说说promise是什么

推导promise的进化 下面代码需要事件循环基础,不了解可以点击这里查看

1.闭包

let a = { value: 1 }; 
let value = a.value; 
setTimeout(() => {       
    console.log(value);       
    a.value = 2; 
}, 1000); 
setTimeout(() => {        
    console.log(value); // 1 
}, 1000);

2.函数闭包,专门为了异步存在

// 值的引用:改变了栈里面的值,引用的是同一个值,值改变其他引用也会变
// 第一种情况:  let a = 1;
       setTimeout(() => {
          console.log(a);  //1
          a = 2;
        }, 1000);
        setTimeout(() => {
          console.log(a);   //1
        }, 500);
        
        
// 第二种情况:  let a = 1;
       setTimeout(() => {
          console.log(a);  //1
          a = 2;
        }, 1000);
        setTimeout(() => {
          console.log(a);   //2
        }, 1000);
 // 记住了特定时刻的a值

// 对象的引用:对象里面的属性值改变,不会影响其他的引用,这里的value2和a存储在不同的空间中,互不影响         
    const a = { value: 1 };         
    const value2 = a.value; // a.value 是右值         
    // const {value2} = a // 解构赋值         
    setTimeout(() => {           
        console.log(value2);   //1           
    a.value = 2;         
    }, 1000);         
    setTimeout(() => {           
        console.log(value2);    //1         
    }, 2000);

3.异步回调

函数当作参数传递(回调),在异步结果中调用(异步回调),因为函数作用域存在,所以回调在异步中调用时,可以拿到最新的引用

let a = 1; 
function wait(cb) {   
    setTimeout(() => {     
        cb()   
    },1000); 
}
function callback() {
  console.log(a);  //2
}
wait(callback);
a = 2;

4.回调地狱(promise最重要的作用)

回调地狱出现的问题:

  1. 取值引用问题
  2. 常量冲突
  3. 变量遮蔽
  4. 大椎形代码
// 嵌套太多,分不清楚引用的是谁了,后面的变量会遮蔽前面的值 
const a = { value: 1 };         
const { value } = a;         
wait(() => {           
    // 常量冲突           
    const b = 1;           
    console.log(1);           
    wait((res) => {             
        console.log(2);             
        // 变量遮蔽             
        wait((res) => {               
            console.log(res);               
            console.log(3);               
            b = 2;             
        });           
    });         
});

5.promise 用来解决回调地狱的 ( 让异步任务进行同步处理)

function wait(n) {   
    return new Promise((resolve, reject) => {     
    setTimeout(() => {       
            resolve(`等待${n}毫秒`); // .then 的回调,在这里跑
        }, n);     
        // 然后   一段时间以后   
    }); 
} 

wait(1000).then((res) => {  
    console.log(res); 
});

6.promise 链式调用 就是(promise.then())

思想:等待一段时间,干一件事,再等待一段时间,再干一件事 …

function wait(n) {   
    return new Promise((resolve, reject) => {     
        setTimeout(() => {       
            resolve(`等待${n}毫秒`); // .then 的回调,在这里跑
        }, n);    
        // 然后 一段时间以后   
    }); 
} 

wait(1000)   
    .then((res) => {     
        console.log(res);     
        // 当 .then 返回的值是 promise,下一个.then(的参数)是promise的resolve     
        return wait(1000);   
    })   
    .then((res) => {     
        console.log(res);     
        // 当 .then 返回的值,不是 promise 的时候,下一个 .then 就是这个值  
        return "立即执行";   
    })   
    .then((res) => {     
        console.log(res);   
    });

async/await

promise的语法糖 ⽤同步的⽅式,写异步代码

async function asyncFunction() {     
const res1 = await wait(1000);      
console.log(res1);      
const res2 = await wait(1000);      
console.log(res2);      
const res3 = await wait(1000);      
console.log(res3); } 

// 等同于 
function promiseFuction() {      
    wait(1000)      
    .then((res1) => {            
        console.log(res1);            
        return wait(1000);      
    })      
    .then((res2) => {            
        console.log(res2);            
        return wait(1000);      
    })      
    .then((res3) => {            
        console.log(res3);    
    }); 
}

promise拓展

获取⼀个 Promise 列表中,所有 Promise resolve 的值

Promise.all([promise1, promise2]).then((res) => { 
    const [result1, result2] = res; 
});

Promise.race()

获取⼀个 Promise 列表中,第⼀个 resolve 的值

function wait(n) {   
    return new Promise((res) => {     
        setTimeout(() => {       
            console.log(1);       
            res(`等待了${n}毫秒`);       
            console.log(2);     
        }, n);   
    }); 
} 

Promise.race([wait(1000), wait(500), wait(3000)]).then((res) => {   
    console.log("Promise.race", res);   //等待了500毫秒 
});