vue 第四天 Promise用户;then参数;fetch接口调用方法;axios插件;async/await 用法

1.1 接口调用方式

  1. 原生 ajax
  2. 基于 jQuery 的ajax
  3. fetch
  4. axios

这里可以返回一个完整的HTML页面;也可以只返回特定格式的数据,比如json

1.2 URL 地址格式

1. 传统形式的 URL

  1. 格式:schema://host:port/path?query#fragment
    schema:协议。例如http、https、ftp等
    host:域名或者IP地址
    port:端口, http默认端口80,可以省略
    path:路径, 例如/abc/a/b/c
    query :查询参数,例如 uname=lisi&age=12
    fragment :锚点(哈希Hash),用于定位页面的某个位置
  2. 符合规则的URL
    http://www.itcast.cn
    http://www.itcast.cn/java/web
    http://www.itcast.cn/java/web?flag=1
    http://www.itcast.cn/java/web?flag=1#function

--------------- Promise 用法 ---------------

2.1 异步调用

  1. 异步效果分析:
    1.定时任务
    2.Ajax
    3.事件函数
  2. 多次异步调用的依赖分析
  3. 多次异步调用的结果顺序不确定
     嵌套达到顺序一致
	        $.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)
                            }
                        });
                    }
                });
            }
        });
  1. 异步调用结果如果存在依赖需要嵌套

2.2 Promise 概述

Promise 是异步编程的一种解决方案,从语法上讲,Promise是一个对象,从它可以获取异步操作的消息

使用 Promise 主要有以下好处:

  1. 可以避免多层异步调用嵌套问题(回调地狱)
  2. Promise 对象提供了简洁的API,使得控制异步操作更加容易

2.3 Promise 基本用法

  1. 实例化 Promise 对象,构造函数中传递函数,该函数中用于处理异步任务
  2. resolve 和 reject 两个参数用于处理成功和失败两种情况,并通过 p.then 获取处理结果
        var p = new Promise(function(resolve, reject) {
            // 这里用于实现异步任务
            setTimeout(function() {
                var flag = false;
                if (flag) {
                    // 正常情况
                    resolve('hello'); .//成功时调用 resolve()
                } else {
                    // 异常情况
                    reject('出错了');  // 失败时调用 reject()
                }
            }, 100);
        });
        p.then(function(data) {
            console.log(data) // 从 resolve 获取正确结果
        }, function(info) {
            console.log(info)  // 从 reject 获取错误信息
        });

2.4 基于Promise处理Ajax请求

1. 处理原生Ajax

    function queryData(url) {
      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) {
            // 处理正常的情况
            resolve(xhr.responseText);
          }else{
            // 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }

2. 发送多次ajax请求

    发送多个ajax请求并且保证顺序
    
    queryData('http://localhost:3000/data')
      .then(function(data){
        console.log(data)
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
        console.log(data);
        return queryData('http://localhost:3000/data2');
      })
      .then(function(data){
        console.log(data)
      });

2.5 then参数中的函数返回值

1. 返回 Promise 实例对象

返回的该实例对象会调用下一个 then

// An highlighted block
var foo = 'bar';

2. 返回普通值

返回的普通值会直接传递给下一个 then,通过 then 参数中函数的参数接收该值

    /*
      then参数中的函数返回值
    */
    function queryData(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 处理正常的情况
            resolve(xhr.responseText);
          }else{
            // 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }
    queryData('http://localhost:3000/data')
      .then(function(data){  //返回的该实例对象会调用下一个 then
        return queryData('http://localhost:3000/data1');
      })
      .then(function(data){
        return new Promise(function(resolve, reject){
          setTimeout(function(){
            resolve(123);
          },1000)
        });
      })
      .then(function(data){
        return 'hello';
      })
      .then(function(data){
        console.log(data)
      })

2.6 Promise常用的API

1. 实例方法

  1. p.then() 得到异步任务的正确结果
  2. p.catch() 获取异常信息
  3. p.finally() 成功与否都会执行(尚且不是正式标准)
    foo()
      .then(function(data){
        console.log(data)
      })
      .catch(function(data){
        console.log(data)
      })
      .finally(function(){
        console.log('finished')
      });

    // 两种写法是等效的
    foo()
      .then(function(data){
        console.log(data)
      },function(data){
        console.log(data)
      })
      .finally(function(){
        console.log('finished')
      });

2. 对象方法

  1. Promise.all() 并发处理多个异步任务,所有任务都执行完成才能得到结果
  2. Promise.race() 并发处理多个异步任务,只要有一个任务完成就能得到结果
    function queryData(url) {
      return new Promise(function(resolve, reject){
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function(){
          if(xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 处理正常的情况
            resolve(xhr.responseText);
          }else{
            // 处理异常情况
            reject('服务器错误');
          }
        };
        xhr.open('get', url);
        xhr.send(null);
      });
    }

    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){
    //   console.log(result)
    // })
    Promise.race([p1,p2,p3]).then(function(result){
      console.log(result)
    })

--------------- 接口调用-fetch用法 ---------------

3.1 fetch 概述

1. 基本特性

  1. 更加简单的数据获取方式,功能更强大、更灵活,可以看做是xhr的升级版
  2. 基于Promise实现

2. 语法结构

        fetch('http://localhost:3000/fdata').then(function(data) {
            // text()方法属于fetchAPI的一部分,它返回一个Promise实例对象,
          //  用于获取后台返回的数据
            return data.text();
        }).then(function(ret) {
     	   // 注意这里得到的才是最终的数据
            console.log(ret);
        })

3.2 fetch请求参数

1. 常用配置选项

  1. method(String): HTTP请求方法,默认为GET (GET、POST、PUT、DELETE)
  2. body(String): HTTP的请求参数
  3. headers(Object): HTTP的请求头,默认为{}
fetch('/abc' , {
    method:get}).then(data=>{
    return data.text();
 }).then(ret=>{
    // 注意这里得到的才是最终的数据
    console.log(ret);
 });

2. GET请求方式的参数传递

    // GET参数传递-传统URL
    fetch('http://localhost:3000/books?id=123', {
      method: 'get'
    })
      .then(function(data){
        return data.text();
      }).then(function(data){
        console.log(data)
      });

    // GET参数传递-restful形式的URL
    fetch('http://localhost:3000/books/456', {
      method: 'get'
    })
      .then(function(data){
        return data.text();
      }).then(function(data){
        console.log(data)
      });

3. DELETE请求方式的参数传递

    // DELETE请求方式参数传递
    fetch('http://localhost:3000/books/789', {
      method: 'delete'
    })
      .then(function(data){
        return data.text();
      }).then(function(data){
        console.log(data)
      });

4. POST请求方式的参数传递

    // POST请求传参
    fetch('http://localhost:3000/books', {
      method: 'post',
      body: 'uname=lisi&pwd=123',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })
      .then(function(data){
        return data.text();
      }).then(function(data){
        console.log(data)
      });

    // POST请求传参
    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请求方式的参数传递

    // PUT请求传参
    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)
      });

3.4 fetch响应结果

响应数据格式

  1. text(): 将返回体处理成字符串类型
  2. json():返回结果和 JSON.parse(responseText)一样
 fetch('/abc' then(data=>{
    // return data.text(); 或者
    return data.json();
 }).then(ret=>{
    console.log(ret);
 });

--------------- 接口调用-axios用法 ---------------

4.1 axios 的基本特性

axios(官网:https://github.com/axios/axios)是一个基于Promise 用于浏览器和 node.js 的 HTTP 客户端。它具有以下特征:

  1. 支持浏览器和 node.js
  2. 支持 promise
  3. 能拦截请求和响应
  4. 自动转换 JSON 数据

4.2 axios 的基本用法

        axios.get('http://localhost:3000/adata').then(function(ret) {
            // 注意data属性是固定的用法,用于获取后台的实际数据
            // console.log(ret.data)
            console.log(ret)
        })

4.3 axios 的常用API

  1. get : 查询数据
  2. post : 添加数据
  3. put : 修改数据
  4. delete :删除数据

4.4 axios 的参数传递

1. GET传递参数

  1. 通过 URL 传递参数
  2. 通过 params 选项传递参数
    // axios get请求传参
    axios.get('http://localhost:3000/axios?id=123').then(function(ret){
      console.log(ret.data) // ?id=123
    })
    axios.get('http://localhost:3000/axios/123').then(function(ret){
      console.log(ret.data) // /123
    })
    axios.get('http://localhost:3000/axios', {
      params: {         // params 格式
        id: 789
      }
    }).then(function(ret){
      console.log(ret.data)
    })

2. DELETE传递参数
3. 参数传递方式与GET类似

    // axios delete 请求传参
    axios.delete('http://localhost:3000/axios', {
      params: {
        id: 111
      }
    }).then(function(ret){
      console.log(ret.data)
    })

3. POST传递参数
4. 通过选项传递参数(默认传递的是 json 格式的数据)

    //方法一  格式问题
    axios.post('http://localhost:3000/axios', {
      uname: 'lisi',
      pwd: 123
    }).then(function(ret){
      console.log(ret.data)
    })

  1. 通过 URLSearchParams 传递参数(application/x-www-form-urlencoded)
    // 方法二
    var params = new URLSearchParams();
    params.append('uname', 'zhangsan');
    params.append('pwd', '111');
    axios.post('http://localhost:3000/axios', params).then(function(ret){
      console.log(ret.data)
    })

4. PUT传递参数

  1. 参数传递方式与POST类似
    // axios put 请求传参
    axios.put('http://localhost:3000/axios/123', {
      uname: 'lisi',
      pwd: 123
    }).then(function(ret){
      console.log(ret.data)
    })

4.5 axios 的响应结果

响应结果的主要属性

  1. data : 实际响应回来的数据
  2. headers :响应头信息
  3. status :响应状态码
  4. statusText :响应状态信息
  axios.post('/axios-json‘).then(ret=>{
    console.log(ret)
  })

4.6 axios 的全局配置

  1. axios.defaults.timeout = 3000; // 超时时间
  2. axios.defaults.baseURL = ‘http://localhost:3000/app’; // 默认地址
  3. axios.defaults.headers[‘mytoken’] = ‘aqwerwqwerqwer2ewrwe23eresdf23’// 设置请求头 (类似登录密码的那个密匙)
    // 配置请求的基准URL地址
    axios.defaults.baseURL = 'http://localhost:3000/';
    // 配置请求头信息
    axios.defaults.headers['mytoken'] = 'hello';
    axios.get('axios-json').then(function(ret){
      console.log(ret.data.uname)
    })

4.7 axios拦截器

1. 请求拦截器

    axios.interceptors.request.use(function(config) {
      console.log(config.url)
      config.headers.mytoken = 'nihao';
      return config;
    }, function(err){
      console.log(err)
    })

2. 响应拦截器

    axios.interceptors.response.use(function(res) {
      // console.log(res)
      var data = res.data;
      return data;
    }, function(err){
      console.log(err)
    })
    axios.get('http://localhost:3000/adata').then(function(data){
      console.log(data) // 这里的 data 等于 原本的  ret.data
    })

------------- 接口调用-async/await用法 -------------

5.1 async/await 的基本用法

  1. async/await是ES7引入的新语法,可以更加方便的进行异步操作
  2. async 关键字用于函数上(async函数的返回值是Promise实例对象)
  3. await 关键字用于 async 函数当中(await可以得到异步的结果)
    async function queryData() {
      var ret = await axios.get('adata');
      console.log(ret.data)
      return ret.data;
    }

5.2 async/await 处理多个异步请求

    axios.defaults.baseURL = 'http://localhost:3000';

    async function queryData() {
      var info = await axios.get('async1');
      var ret = await axios.get('async2?info=' + info.data);
      return ret.data;
    }

    queryData().then(function(data){
      console.log(data)
    })

6. 基于接口的案例

图书相关的操作基于后台接口数据进行操作
需要调用接口的功能点

  1. 图书列表数据加载 GET http://localhost:3000/books
  2. 添加图书 POST http://localhost:3000/books
  3. 验证图书名称是否存在 GET http://localhost:3000/books/book/:name
  4. 编辑图书-根据ID查询图书信息 GET http://localhost:3000/books/:id
  5. 编辑图书-提交图书信息 PUT http://localhost:3000/books/:id
  6. 删除图书 DELETE http://localhost:3000/books/:id

----------------------------- promise 和 acync await 补充

  1. 如何声明一个Promise
new Promise(function(resolve, reject){ })
  1. 如果想让Promise成功执行下去,需要执行resolve,如果让它失败执行下去,需要执行reject
new Promise(function(resolve, reject) { 
    resolve('success')  // 成功执行
}).then(result => {
    alert(result)
})

new Promise(function(resolve, reject) { 
    reject('fail')  // 成功执行
}).then(result => {
    alert(result)
}).catch(error => {
     alert(error)
})
  1. 如果想终止在某个执行链的位置,可以用 Promise.reject(new Error())
new Promise(function(resolve, reject) {
    resolve(1)
}).then(result => {
    return result + 1
}).then(result => {
    return result + 1
}).then(result => {
  return  Promise.reject(new Error(result + '失败'))
   // return result + 1
}).then(result => {
    return result + 1
}).catch(error => {	
    alert(error)
})

异步编程的终极方案 async /await

  1. async 和 await实际上就是让我们像写同步代码那样去完成异步操作
  2. await 表示强制等待的意思,await关键字的后面要跟一个promise对象,它总是等到该promise对象resolve成功之后执行,并且会返回resolve的结果
 async test () {
      // await总是会等到 后面的promise执行完resolve
      // async /await就是让我们 用同步的方法去写异步
      const result = await new Promise(function (resolve, reject) {
        setTimeout(function () {
          resolve(5)
        }, 5000)
      })
      alert(result)
    }
    上面代码会等待5秒之后,弹出5
  1. async 和 await必须成对出现
    由于await的强制等待,所以必须要求使用await的函数必须使用async标记, async表示该函数就是一个异步函数,不会阻塞其他执行逻辑的执行
async test () {
      const result = await new Promise(function(resolve){  
         setTimeout(function(){
             resolve(5)
         },5000)
       })
       alert(result)
    },
    test1(){
      this.test()
      alert(1)
    }
  1. 通过上面的代码我们会发现,异步代码总是最后执行,标记了async的函数并不会阻塞整个的执行往下走

如果你想让1在5弹出之后再弹出,我们可以这样改造

 async test1(){
     await this.test()
      alert(1)
   }
// 这充分说明 被async标记的函数返回的实际上也是promise对象

如果promise异常了怎么处理?

 promise可以通过catch捕获,async/ await捕获异常要通过 try/catch

   async  getCatch () {
      try {
        await new Promise(function (resolve, reject) {
          reject(new Error('fail'))
        })
        alert(123)
      } catch (error) {
        alert(error)
      }
   }

全部代码

<template>
  <div id="app">
    <el-card class="login-card">
      <!-- 放置表单容器 -->
      <el-form ref="loginForm" :model="loginForm" :rules="loginRules" style="margin-top:50px">
        <!-- 表单项 -->
        <el-form-item prop="mobile">
            <!-- 输入框 -->
            <el-input v-model="loginForm.mobile" placeholder="请输入您的手机号"></el-input>
        </el-form-item>
        <el-form-item prop="password">
            <!-- 输入框 -->
            <el-input v-model="loginForm.password" placeholder="请输入您的密码"></el-input>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" style="width: 100%" @click="login">登录</el-button>
        </el-form-item>
      </el-form>
      <el-button type="primary" @click="test">测试async</el-button>
      <el-button type="primary" @click="test1">测试async1</el-button>
      <el-button type="primary" @click="getCatch">捕获异常</el-button>

    </el-card>
  </div>
</template>

<script>

export default {
  name: 'App',
  components: {
    
  },
  data () {
    const checkMobile = function (rule, value, callback) {
      // 校验的是value
      // 第三位必须是9
      value.charAt(2) === "9" ? callback() : callback(new Error("手机号第三位必须是9"))
    }
    return {
      // 数据对象
      loginForm: {
        //  校验的字段
        mobile: '',
        password: '' 
      },
      // 校验规则
      // { key: value }
      loginRules: {
        mobile: [{ required: true, message: '手机号不能为空', trigger: 'blur' }, {
          trigger: 'blur',
          message: '手机号格式不正确',
          pattern: /^1[3-9]\d{9}$/  // 校验手机号
        }, {
          trigger: 'blur',
          validator: checkMobile
        }],
        password: [{ required: true, message: '密码不能为空', trigger: 'blur' },{
          min: 6, max: 16, trigger: 'blur', message: '密码的长度为6-16位'
        }]
      }
    }
  },
  methods: {
    login () {
      // this.$refs.loginForm.validate(isOK => {
      //     if (isOK) {
      //       // 表示 校验是通过
      //       console.log("校验通过")  // 去做接下来的业务
      //     }
      // })
      // then是成功校验 catch是失败校验
      this.$refs.loginForm.validate().then(() => {
        console.log("成功")
      }).catch(() => {
        console.log("失败")
      })
    },
   async test () {
      // await后面跟上一个promise对象 总是会等到promise对象 resolve结束之后 接收它的结果 执行下面的逻辑
      // await必须和async配合使用  必须在await的父级函数的位置 标记一个async
     const result =  await new Promise(function(resolve){
          // 5秒之后执行resolve
          setTimeout(function() {
            resolve(100)
          }, 5000)
        })
       alert(result)
    },
  async test1() {
     await this.test() // 调用test方法 标记了async的方法是 异步的方法
      // 异步方法不会阻塞其他逻辑的执行
      alert(1234)
    },
   async getCatch() {
     try {
      const  result = await new Promise(function(resolve, reject) {
       reject("失败了")
     })
     alert(result)
     } catch (error) {
         alert(error)
     }
  }
  },

}
</script>

<style>
#app {
 width: 100%;
 height: 100vh;
 background-color: pink;
 display: flex;
 justify-content: center;
 align-items: center;
}
.login-card {
  width: 440px;
  height: 300px;
}
</style>


版权声明:本文为m0_55170432原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。