js处理异步的几种方式

同步、异步

1.造成原因:js是单线程的语言

2.概念:

  • 同步任务:实时处理 在主线程上排队执行的任务,按照先后顺序执行
  • 异步任务:分时处理 不进入主线程、而进入"任务队列"的任务,只有等主线程任务执行完毕,"任务队列"开始通知主线程,请求执行任务,该任务才会进入主线程执行
  • 异步模式可以一起执行多个任务

3.js处理异步的几种方式

1. 底层原理

XML 的英文全称是 EXtensible Markup Language,即可扩展标记语言

1.1 使用xhr发起GET请求

// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数
xhr.open('GET', 'http://www.shanshan.top:3006/api/getlist?id=1&list=统计') //?id=1查询字符串
// 3. 调用 send 函数
xhr.send()
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
    当 readyState 等于 4 且状态为 200 时,表示响应已就绪:
  if (xhr.readyState === 4 && xhr.status === 200) {
     // 获取服务器响应的数据
     console.log(xhr.responseText)
   }
}

1.2 使用xhr发起POST请求

// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数
xhr.open('POST', 'http://www.shanshan.top:3006/api/addlist')
// 3. 设置 Content-Type 属性(固定写法)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 4. 调用 send 函数
xhr.send('bookname=三毛&author=张三&publisher=本地图书出版社')
// 5. 监听事件
//onreadystatechange 存储函数,每当 readyState 属性改变时,就会调用该函数
xhr.onreadystatechange = function () {
   // 对象的 readyState 属性,用来表示当前 Ajax 请求所处的状态 
   // 当 readyState 等于 4 且状态为 200 时,表示响应已就绪:
  if (xhr.readyState === 4 && xhr.status === 200) {
      // 获取服务器响应的数据
    console.log(xhr.responseText)
  }
}

1.3 FormData对象管理表单数据

Ajax 操作往往用来提交表单数据。为了方便表单处理,HTML5 新增了一个 FormData 对象,可以模拟表单操作:

 // 1. 新建 FormData 对象
 var fd = new FormData()
 // 2. 为 FormData 添加表单项
 fd.append('uname', 'zs')
 fd.append('upwd', '123456')
 // 3. 创建 XHR 对象
 var xhr = new XMLHttpRequest()
 // 4. 指定请求类型与URL地址
 xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
 // 5. 直接提交 FormData 对象,这与提交网页表单的效果,完全一样
 xhr.send(fd)

FormData对象也可以用来获取网页表单的值,示例代码如下:

// 获取表单元素
var form = document.querySelector('#form1')
// 监听表单元素的 submit 事件
form.addEventListener('submit', function(e) {
 e.preventDefault()
 // 根据 form 表单创建 FormData 对象,会自动将表单数据填充到 FormData 对象中
 var fd = new FormData(form)
 var xhr = new XMLHttpRequest()
 xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
 xhr.send(fd)
 xhr.onreadystatechange = function() {}
})

2. 原生ajax

2.1 jQuery中的Ajax

$.ajax({
    type:'GET',    //请求方式
    url:'http://www.shanshan.top:3006/api/getlist',   //请求的url地址
    data:{id:1},   //这次请求需携带的参数
    success:function(res){    //请求成功之后的回调函数
        console.log(res)      //res 后台返回的数据
    }
})

$.ajax({
    type:'POST',
    url:'http://www.shanshan.top:3006/api/addlist',
    data:{
        name:'张三',
        sex:'男'
    },
    success:function(res){
        console.log(res)
    }
})

2.2 通过Ajax提交表单数据

<from id="from1">
        <input type="text" name="username">
        <input type="password" name="password">
        <button type="submit">提交</button>
</from>

<script>
   $('#from1').submit(function (e) {
      e.preventDefault() //阻止表单的默认提交和页面的跳转
       var data = $(this).serialize() //一次性获取表单的数据,必须为每个表单元素添加 name 属性
    })
</script>

多次调用ajax时,不是按照书写ajax代码的顺序返回结果,如果存在依赖关系就需要嵌套,会造成回调地狱

 $.ajax({
      url: 'http://localhost:3000/data',
      success: function(data) {
        console.log(data)
        $.ajax({
          url: 'http://localhost:3000/data1',
          success: function(data) {
            console.log(data)
            $.ajax({
              url: 'http://localhost:3000/data2',
              success: function(data) {
                console.log(data)
              }
            });
          }
        });
      }
    });

3. promise对象主要解决异步深层嵌套造成回调地狱的问题--es6

promise对象是一个构造函数,用来生成Promise实例

3.1 基本用法

function timeout() {
     var p = new Promise(function(resolve,reject){
     //异步操作
        setTimeout(function(){
        var flag = false;
        if(flag) {
          //3.失败时调用resolve()
          resolve('hello');
        }else{
          //4.成功是调用reject()
          reject('出错了');
        }
      }, 100);
      });
     return p
}
//p.then获取处理结果
p.then(function(ret){
  从resolve得到的正常结果
},function(ret){
   从reject得到的错误信息
})

3.2 基于Promise发送Ajax请求

 <script type="text/javascript">
    /*
      基于Promise发送Ajax请求
    */
    function queryData(url) {
     #   1.1 创建一个Promise实例
      var p = new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            # 1.2 处理正常的情况
            resolve(xhr.responseText);
          }else{
            # 1.3 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
      return p;
    }
    
    #发送多个ajax请求并且保证顺序

    多个ajax任务通过 .then 的方式变成了线性关系,保证的执行的顺序
    queryData('http://localhost:3000/data')
      .then(function(data){
        console.log(data)
        //return的是一个新的Promise对象,下一个then的调用者就是上一个return出来的Promise对象
        return queryData('http://localhost:3000/data1'); 
      })
      .then(function(data){     //data接收上一个异步任务返回的结果
        console.log(data);
        return queryData('http://localhost:3000/data2');
      })
      .then(function(data){     //p.then()得到异步任务的正确结果  resolve中的信息
        console.log(data)
      })
      .catch(function(data){    //p.catch()获取异常信息  reject中的信息
        console.log(data)
      })
      .finally(function(){  	//p.finally()成功与否都会执行(不是正式标准
      	console.log("成功与否都会执行")
      })
  </script>
  • 在then方法中函数的返回值,你也可以直接return数据而不是Promise对象,在后面的then中就可以接收到数据了

3.3 Promise常用的API

1.实例方法

  • p.then ( ) 得到异步任务的正确结果 resolve中的信息
  • p.catch ( ) 获取异常信息 reject中的信息
  • p.finally ( ) 成功与否都会执行(不是正式标准)

2.对象方法

.all()

  • Promise.all方法接受一个数组作参数,数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise,该项会被用Promise.resolve转换为一个promise)。它的状态由这三个promise实例决定

  • 并发处理多个异步任务,所有任务都执行完成才能得到结果

.race()

  • Promise.race方法同样接受一个数组作参数。当p1, p2, p3中有一个实例的状态发生改变(变为fulfilledrejected),p的状态就跟着改变。并把第一个改变状态的promise的返回值,传给p的回调函数

  • 并发处理多个异步任务,只要有一个任务完成就能得到结果

    
    function queryData(url) {
     #   1.1 创建一个Promise实例
      var p = new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            # 1.2 处理正常的情况
            resolve(xhr.responseText);
          }else{
            # 1.3 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
      return p;
    }
    
/*
   Promise常用API-对象方法
*/  
var p1 = queryData('http://localhost:3000/a1');
var p2 = queryData('http://localhost:3000/a2');
var p3 = queryData('http://localhost:3000/a3');

Promise.all([p1,p2,p3]).then(function(result){
 //all 中的参数  [p1,p2,p3]   和 返回的结果一 一对‘应["TOM", "JERRY", "SPIKE"]
   console.log(result) //["TOM", "JERRY", "SPIKE"]
})

Promise.race([p1,p2,p3]).then(function(result){
 // 由于p1执行较快,Promise的then()将获得结果'P1'。   p2,p3仍在继续执行,但执行结果将被丢弃。
 console.log(result) // "TOM"
})

4.接口调用---fetch --- xhr的升级版

fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象

4.1 基本用法
  <script type="text/javascript">
    /*
      Fetch API 基本用法    fetch(url).then()
     	第一个参数请求的路径   Fetch会返回Promise   所以我们可以使用then 拿到请求成功的结果 
    */
    fetch('http://localhost:3000/fdata').then(function(data){
      // text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,用于获取后台返回的数据
      return data.text();
    }).then(function(data){
      //   在这个then里面我们能拿到最终的数据  
      console.log(data);
    })
  </script>

4.2 fetch API 中的 HTTP 请求

1 GET参数传递 - 传统URL 通过url ? 的形式传参

fetch('http://localhost:3000/books?id=123', {
            	# get 请求可以省略不写 默认的是GET 
                method: 'get'
            })
            .then(function(data) {
            	# 它返回一个Promise实例对象,用于获取后台返回的数据
                return data.text();
            }).then(function(data) {
            	# 在这个then里面我们能拿到最终的数据  
                console.log(data)
            });

2 GET参数传递 restful形式的URL 通过/ 的形式传递参数 即 id = 456 和id后台的配置有关

fetch('http://localhost:3000/books/456', {
            	# get 请求可以省略不写 默认的是GET 
                method: 'get'
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

3 DELETE请求方式参数传递 删除id 是 id=789

fetch('http://localhost:3000/books/456', {
            	# get 请求可以省略不写 默认的是GET 
                method: 'get'
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

4 POST请求传参

fetch('http://localhost:3000/books', {
                method: 'post',
            	# 3.1  传递数据 
                body: 'uname=lisi&pwd=123',
            	#  3.2  设置请求头 
                headers: {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });


fetch('http://localhost:3000/books', {
                method: 'post',
                body: JSON.stringify({
                    uname: '张三',
                    pwd: '456'
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
       })
       .then(function(data) {
           return data.text();
       }).then(function(data) {
           console.log(data)
       });

5 PUT请求传参 修改id 是 123 的

fetch('http://localhost:3000/books/123', {
                method: 'put',
                body: JSON.stringify({
                    uname: '张三',
                    pwd: '789'
                }),
                headers: {
                    'Content-Type': 'application/json'
                }
            })
            .then(function(data) {
                return data.text();
            }).then(function(data) {
                console.log(data)
            });

fetchAPI 中 响应格式

fetch('http://localhost:3000/json').then(function(data){
  // return data.json();   //  将获取到的数据使用 json 转换对象
  return data.text(); //  //  将获取到的数据 转换成字符串 
}).then(function(data){
   // console.log(data.uname)
   // console.log(typeof data)  string
   var obj = JSON.parse(data); //转化成对象
   console.log(obj.uname,obj.age,obj.gender)
})

5.接口调用--axios

Axios 是一个基于 promise 的 HTTP 库,是专注于网络数据请求的库,可以用在浏览器和 node.js 中。

5.1 综合写法

axios({
	method:"请求的方式"
	url:"请求的地址"
	data:发送的数据
	headers:请求头
}).then(()=>{})
.catch(()=>{})

5.2 axios 全局配置

#  配置公共的请求头 
axios.defaults.baseURL = 'https://api.example.com';
#  配置 超时时间
axios.defaults.timeout = 2500;
#  配置公共的请求头
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
# 配置公共的 post 的 Content-Type
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

5.3 axios 拦截器

5.3.1 请求拦截器

  • axios.interceptors.request.use(function(config) {
          console.log(config.url)
          # 1.1  任何请求都会经过这一步   在发送请求之前做些什么   
          config.headers.mytoken = 'nihao';
          # 1.2  这里一定要return   否则配置不成功  
          return config;
        }, function(err){
           #1.3 对请求错误做点什么    
          console.log(err)
        })
    

5.3.2 响应拦截器

  • axios.interceptors.response.use(function(res) {
          #2.1  在接收响应做些什么  
          var data = res.data;
          return data;
        }, function(err){
          #2.2 对响应错误做点什么  
          console.log(err)
        })
    

5.4 创建axios实例

  • const instance = axios.create({
      baseURL: 'https://some-domain.com/api/',
      timeout: 1000,
      headers: {'X-Custom-Header': 'foobar'}
    });
    

6. **async await **让异步代码看起来更像同步代码 --ES7

async关键字 放到函数前面 (返回值是一个promise实例对象)

await关键字 只能在使用async定义的函数中使用(得到异步的结果,await只能得到成功的结果,如果想要得到失败的结果,只能用trycatch)

6.1处理单个异步请求

async getFaceResult () {
//用的是try/catch来捕获异常,把await放到try中进行执行
//如有异常,就使用catch进行处理,不会影响后面的代码
      try {
         let location = await getLocation()
      } catch(err) {
         console.log("错误",err)
    }
}

6.2处理多个异步请求

async getFaceResult () {
      try {
          // 添加await之后 当前的await 返回结果之后才会执行后面的代码
         let location = await getLocation()
         let ret = await getList()
      } catch(err) {
         console.log("错误",err)
    }
}
posted @ 2021-01-11 22:24  歇歇吧  阅读(1033)  评论(0编辑  收藏  举报