zoukankan      html  css  js  c++  java
  • 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)
        }
    }
    
  • 相关阅读:
    【 socke】C# socket端口复用-多主机头绑定
    【网络】 NAT
    【socket】高级用法-ReceiveMessageFrom
    【socket】高级用法-异步
    C# GET 和 SET作用
    多态是什么意思?
    LINQ(LINQ to Entities)
    LINQ(隐式表达式、lambda 表达式)
    LINQ(LINQ to DataSet)
    C# 中的委托和事件
  • 原文地址:https://www.cnblogs.com/33shan/p/14264741.html
Copyright © 2011-2022 走看看