vue-promise-axios

本文详细介绍了Vue中使用Axios发送请求,包括Promise的使用,最佳实践,以及如何处理异步回调。文章还探讨了restful风格API,模拟数据的静态和动态Mock方法,如webpack-dev-server和Mock.js。此外,还讲解了axios的配置优先级、拦截器和数据处理,以及在项目中如何进行axios的二次封装。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 回调函数

1.1 回调函数定义:

① 函数是不是你定义的 你定义的

② 函数你要有没有调用 你没调用

③ 最终函数有没有被执行 最终执行了

1.2 回调函数分类:

同步的回调:数组api中的回调函数基本都是同步的;promise的执行器是同步的

异步的回调:定时器的回调 dom事件的回调 ajax请求的回调

遇到异步回调函数需注意以下两点:

① 回调什么时候进队列

② 回调什么时候被执行

内存结构:堆 栈 队列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2zfZO7rw-1626050796268)(D:\class\vue\02-vue\code\day07(axios)]\01_异步&单线程\定时器\事件循环模型.png)

//最快一秒钟同时输出5个5   
for (var i 0; i < 5; i++){
	setTimeout(function() {
		console.log(i)   55555
	},1000)
}
//...耗时的操作

2 变量的查找规则

  • js中的作用域就是函数作用域!

  • 变量的查找基于作用域链

变量的查找规则:

① 左查询(变量出现在等号的左边使用左查询的规则进行变量查找)

​ 如果整条作用域链中 都没有对应变量的声明 则v8会默认在顶层作用域声明一份

② 右查询(变量出现在等号的非左边使用右查询的规则进行变量查找)

​ 如果整条作用域链中 都没有对应变量的声明 则v8会报错

function wrap(){
        function inner(){
            a = 1;
            console.log(a,"inner")
        }
        inner()
    } 
 wrap()
 console.log(a,"全局")  //1 inner 1 全局

3 Promis实例

3.1 Promise最佳实践

① promise实例是一次性的,一个promise实例实例只能使用一次

② promise构造函数的执行器必须有异步代码,应该在异步对应的回调来合理的调用resolve reject

③ then方法中回调的返回值一般是一个新的promise

3.2 promise重点

① promise的实例对象三种状态是如何切换的 (成功 失败 初始化)

② promise的实例持有值为多少

当通过new Promise创造出来的promise实例; 他状态的改变以及持有的值 都跟执行器有关,new Promise时 执行器先执行 再返回promise实例。

执行器的返回值会被忽略

  • 如果执行器中什么都没有发生,创建出来的promise实例则是初始化状态,持有值是undefined
  • 如果执行器中resolve被调用,创建出来的实例是成功状态,持有的值是resolve函数第一个参数
  • 如果执行器中reject被调用,创建出来的实例是失败状态,持有的值是reject函数第一个参数
  • 如果执行器中发生异常,创建出来的promise实例是失败状态,持有的值是失败原因
    let promsie = new Promise((resolve, reject)=>{
        // 执行器内部的resolve, reject一定要放在一个异步环境下调用!!!
        setTimeout(()=>{
            resolve()
        },2000)
    })

promise是一个状态机,在promise状态改变时, 可以决定其then方法中的两个参数什么时候进队列,谁进队列。

then方法有两个参数是两个回调,这两个回调中的一个回调最终是要进队列的,至于是哪一个回调什么时候进队列取决用这个then方法的promise对象的状态什么时候发生改变,改变成什么状态

//此处代表执行时,promise处于初始化状态
let promise = promise.then(() =>{},()=>{})

then方法返回一个新的Promise,而它的行为与then中的回调函数的返回值有关:

  • 如果then中的回调函数返回一个值,那么then返回的Promise将会成为成功状态,promise持有的值就是该返回值。

  • 如果then中的回调函数返回一个Promise,那么then返回的Promise会继承他的状态和值

  • 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为失败状态,promise持有的值就是错误原因

    //此处代表执行时,promise处于初始化状态
    promise.then(()=>{},()=>{})
    

4 promise面试题

    // 输出: 1 2 10 5 6 8 9 3

    //p2 创建完就是成功状态 持有的值为5
    //p1 创建完就是成功状态 持有的值为6
    //p3 创建完就是成功状态 持有的值为9

    const p1 = () => (new Promise((resolve, reject) => {
        console.log(1);
        let p2 = new Promise((resolve, reject) => {
            console.log(2);
            const timeOut1 = setTimeout(() => {
                console.log(3);
                resolve(4);
            }, 0)
            resolve(5);
        });
        resolve(6);
        p2.then((arg) => {
            console.log(arg);
        });
    }));

    const timeOut2 = setTimeout(() => {
        console.log(8);
        const p3 = new Promise(reject => {
            reject(9);
        }).then(res => {
            console.log(res)
        })
    }, 0)


    p1().then((arg) => {
        console.log(arg);
    });
    console.log(10);

5 async&await

async函数返回一个新的promise,而他的行为与async函数的代码体有关

  • 如果async函数代码体返回一个值,那么async函数返回的promise将会成为成功状态,promise持有的值就是该返回值
  • 如果async函数代码体返回一个promise,那么async函数返回的promise与当前代码体返回的promise一致
  • 如果async函数代码体抛出一个错误,那么async函数返回的promise将会成为失败状态,promise的值就是错误原因
//await等于一个promise,当等待的promise状态明确之后,async函数才会继续往下执行
 (async function(){
        try {
            const {data:{items}} = await axios.get("https://api.github.com/search/users?q=damu")
            let login = items[0].login;
            const {data:dataForRepos} = await axios.get(`https://api.github.com/users/${login}/repos`)
            let repname = dataForRepos[0].name;
            const data = await axios.get(`https://api.github.com/repos/${login}/${repname}/issues`)
            console.log(data)
        } catch(error) {
            console.log((error))
        }    
    })()

总结:

① async函数的执行结果是一个promise

② await通常等待是一个promise

async function getLogin(){
	const {data:{items}} = await axios.get("https://api.github.com/search/users?q=damu");	
        let  login = items[0].login;
        return login
    }
......
(async function (){
        const login = await getLogin()
        const repname = await getRepname(login)
        const data = await getIssues(login,repname)
        console.log(data);
    })()

6 axios

	axios.get("https://api.github.com/search/users?q=damu").then(({data:{items}}) =>{
        //console.log(items)   //得到所有带有damu名字的用户
        let login = items[0].login;
        return axios.get(`https://api.github.com/users/${login}/repos`)
    }).then(({data}) =>{
        //console.log(data)  //得到所有的仓库
        let login = data[0].owner.login;
        let repname = data[0].name;
        return axios.get(`https://api.github.com/repos/${login}/${repname}/issues`)
    }).then((data) => {
        console.log(data)  //得到仓库中的issues
    }).catch((err) =>{
        // 处理全程的异常处理,若有错误,异常穿透,打印错误信息
        console.log(err)
    })

axios

axios文档: http://www.axios-js.com/zh-cn/docs/
github开发者文档: https://docs.github.com/en
    根路径: https://api.github.com
    查询用户: https://api.github.com/search/users?q=damu
    查询指定用户的仓库:https://api.github.com/users/${login}/repos
 查询指定用户仓库的issues: https://api.github.com/repos/${login}/${repname}/issues

安装axios:npm i axios

在项目的入口文件引入axios:import axios from “axios”

使用axios发生基本请求

7 restful 风格 api

7.1 code:

200:请求成功 返回内容
204:请求成功但不返回内容
403:权限不够,拒绝访问
404:接口未定义
412:params数据有问题
422:query数据有问题
500:服务器错误

7.2 method:

① get(查询 获取所有的issues) : /repos/{owner}/{repo}/issues

<div class="hello">
    <input type="text" v-model="username">
   <button @click="getIssues">获取仓库内容</button>
   <ul v-if="issues.length" class="issues">
      <li v-for="issue in issues" :key="issue.id">
       {{issue.title}}:{{issue.body}}
      </li>
   </ul>
  </div>
import axios from "axios"
export default {
  name: 'issues',
  data() {
    return {
      issues:[],
      username:'betterDamu'  //输入框中的内容即是仓库名字
    }
  },
  methods:{
    // 获取仓库中的数据
   async getIssues(){
      const {data} = await axios({  ///repos/{owner}/{repo}/issues
        url:`https://api.github.com/repos/${this.username}/bj_181130/issues`,
        method:"get"
      })
      console.log(data)  //得到所有的仓库数据,可以结构赋值只拿到data数据
      this.issues = data
    },
  }
}

② get(查询 获取指定的issues) : /repos/{owner}/{repo}/issues/{issue_number}

<a href="#" @click.prevent="getIssue(issue.number)">{{issue.title}}:{{issue.body}}</a>
// 点击获取仓库中的一个内容并输出
    async getIssue(issue_number) {
      const {data} = await axios({ //repos/{owner}/{repo}/issues/{issue_number}     url:`https://api.github.com/repos/${this.username}/bj_181130/issues/${issue_number}`,
          method:"get"
      })
      console.log(data)
    }

③ post(新增) : /repos/{owner}/{repo}/issues

新增接口,登录状态才能提问题,需要权限 github-setting-developer settings- personal access tokens

 <button @click="addIssue">给仓库增加一个内容</button>
 // 给仓库新增一个内容
    async addIssue() {
      const {data} = await axios({ //repos/{owner}/{repo}/issues
        url:`https://api.github.com/repos/${this.username}/bj_181130/issues`,
        method:"post",
        data:{
          title:"abc",
          body:"def",
        },
        headers:{
          Authorization:"token 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",
        }
      })
      //界面要刷新
      await this.getIssues()
      //.......必须要等界面刷新成功之后才能执行的后续逻辑
  }

④ patch(局部修改): /repos/{owner}/{repo}/issues/{issue_number}

<button @click="updateIssue(issue.number)">修改</button>
 // 进行局部更新 修改仓库中的一个内容
    async updateIssue(issue_number) {
      await axios({  ///repos/{owner}/{repo}/issues/{issue_number}
        url:`https://api.github.com/repos/${this.username}/bj_181130/issues/${issue_number}`,
        method:"patch",
        data:{
          title:"123456"
        },
        headers:{
           Authorization:"token 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",
        }
      })
      await this.getIssues()
    },

⑤ put(锁) : /repos/{owner}/{repo}/issues/{issue_number}/lock

 <button @click="suoIssue(issue.number)"></button>
 async suoIssue(issue_number) { 
      await axios({  ///repos/{owner}/{repo}/issues/{issue_number}
        url:`https://api.github.com/repos/${this.username}/bj_181130/issues/${issue_number}/lock`,
        method:"put",
        headers:{
           Authorization:"token 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",
        }
      })
      await this.getIssues()
    },

⑥ delete(解锁) : /repos/{owner}/{repo}/issues/{issue_number}/lock

<button @click="deleteIssue(issue.number)">解锁</button>
    async deleteIssue(issue_number) { 
      await axios({  ///repos/{owner}/{repo}/issues/{issue_number}
        url:`https://api.github.com/repos/${this.username}/bj_181130/issues/${issue_number}/lock`,
        method:"delete",
        headers:{
           Authorization:"token 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",
        }
      })
      await this.getIssues()
    },

8 使用axios发送请求(实现对issues的CDUR)

8.1 通过axios函数发送请求

整个项目的所有模块使用同一个axios函数

import axios from "axios"
① axios (config) 
② axios(url,config) //config要删除URL配置
	config:{
		url:"请求方式",
		method:"请求方式",
		data:{} ,//请求体
		headers:{authorization},//请求头
		params:{},//这是query数据 query=params
		timeout:1000,//超时时间:请求发送的时间超过这个这个时间,会取消请求
		baseURL:基地址
}

8.2 请求方法的别名

③ axios.method(url,data,config)//config中要剔除url,method,data
 async getIssues(){
      const {data} = await axios.get(`https://api.github.com/repos/${this.username}/bj_181130/issues`,{  
        method:"get"
      })
    }

9 并发请求

axios.all(迭代器)
axios.spread(callback)
promise.all() 返回一个promise   建议用这个
   const data =  await Promise.all[axios1(),axios2()]   
   data[0]  axios1请求对应的数据
   data[1]  axios2请求对应的数据
	async created() {
      const data = await Promise.all([
        axios.get(`https://api.github.com/repos/betterdamu/bj_181130/issues`,{
          headers:{
            Authorization:"token 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"
          }
        }),
        axios.get(`https://api.github.com/search/users?q=damu`,{
          headers:{
            Authorization:"token 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"
          }
      })])
        console.log(data[0]); // 第一个请求的数据
        console.log(data[1]); // 第二个请求的数据
    }

10 创建实例

整个项目的所有模块可以使用不同axios实例来发送请求

src下新建一个api文件夹,文件issues.js 以下方法都支持:

① axios (config)

② axios(url,config) //config要删除URL配置

③ axios.method(url,data,config)//config中要剔除url,method,data

const ins = axios.create([config])
import axios from "axios";
const issuesAxios = axios.create({
  timeout:1000,
  baseURL:"https://api.github.com/",
  headers:{
    Authorization:"token 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"
  }
})

// 添加请求拦截器
issuesAxios.interceptors.request.use(function (config) {
  // config.baseURL="https://api.zdy.com"
  return config;
});

// 添加响应拦截器
issuesAxios.interceptors.response.use(function (response) {
  //响应回来的时 最早可以拿到返回数据的地方
  return response.data;
}, function (error) {
  //错误处理
  return Promise.reject(error);
});


export default issuesAxios

11 axios返回数据的基本格式

{
  // `data` 由服务器提供的响应
  data: {},
  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,
  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',
  // `headers` 服务器响应的头
  headers: {},
   // `config` 是为请求提供的配置信息
  config: {},
 // 'request'
  // `request` is the request that generated this response
  // It is the last ClientRequest instance in node.js (in redirects)
  // and an XMLHttpRequest instance the browser
  request: {}
}

12 axios配置优先级

优先级依次从低到高

全局默认

axios.defaults.baseURL = 'https://api.example.com';

实例特有

 axios.create({
      baseURL: 'https://api.example.com'
    });

发请求时确认

 instance.get('/longRequest', {
      baseURL: 'https://api.example.com'
    });

请求拦截器的第一个回调是最后可以修改配置的地方

13 拦截器

函数级别和实例级别都可以使用拦截器

// 添加请求拦截器    在app.vue函数级别的拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 响应回来的时候 最早可以拿到返回数据的地方
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });

14 前端往后台传递数据的形式

url.params
url.query
body:请求头 一般只有post patch put来支持
headers:请求头

15 处理跨域

① 让所有的跨域请求改向webpack=dev-server代理服务器(它不光还具备静态资源管理的功能,还拥有转发请求的功能):一般都是修改请求的URL

② 设计webpack-dev-server的代理规则

​ 如果用的是vue-cli,这个配置在config/index.js文件中(dev-proxyTable)

③ 必要时要重写path

跨单域 congif-index.js

devServer: {
    proxy: {
      '/api': 'http://localhost:9000',
    },
  },

修改好后修改baseURL:

baseURL:"/api"  //以api开头的

跨多域

devServer: {
    proxy: {
      '/api': {  /api开头的,如/9000/api
        target: 'http://localhost:3000',
        pathRewrite: { '^/api': '' },
      },
    },
  },
 baseURL:"/9000"  //以9000开头的

项目上线时候,进行生产环境打包 npm dev build 只是在自己的webpackdevserver中,提醒运维做跨域处理

如果有coreURL,则优先使用coreURL 可以进行判断,若有跨域问题,优先使用coreURL ,否baseURL

16 axios二次封装

在项目中不会使用

src/api 文件夹

 contact(代表模块名称)
 	axios.js :代表发送请求的工具
 	config.js:代表发送请求的配置
    index.js :引入上述两个文件,再引入util中工具类, 生成所有的请求函数
github  
api.js :统筹所有模块的index.js,将所有的模块都暴露给ming.js

src/util

createForRequest.js 真正发请求的位置 核心代码

src/main.js

import api from "api/api"
Vue.prototype.$api = api

在项目中如何使用

请求相关的信息(URL methods等)还是不会直接出现在组件中,我们会创建一个叫api的目录,这个目录下会有很多模块发送请求的js文件,每个js文件往外暴露当前模块的请求函数(这些请求函数不是自动生成的,而是手动配置的)


17 mock数据

在没有后接口的情况下,如何造假数据(前后端分离)

17.1 通过webpack-dev-server(静态mock)

	//mock数据源 data:当前json的对象
	const appData = require("../data.json")
    const seller = appData.seller
    const goods = appData.goods
    const ratings = appData.ratings
    
    devServer:{
        before(app){  //before 是个钩子 app:express中的核心对象,可以注册后台路由
            //造一些假后台路由,其实没有真正的访问数据库,而是去拿json中数据
            //通过Ajax请求get方法来访问/api/seller,可以等得到对应的回调函数返回的数据
                app.get("/api/seller",(req,res)=>{ 
                  res.json({
                    code:200,
                    data:data.seller
                  })
                })
        } 
    }
//发送请求
async mounted() {
	axios({
		url:"/api/seller",
		method:get
	})
	console.log(data)
}

有后台接口之后,可以把before删掉。

此方法数据是静态的,一成不变的。

17.2 通过mock.js(动态mock)

文档地址:http://mockjs.com/ 生成随机数据,拦截ajax请求

① 安装
npm install mockjs -D
② 基本使用
// 使用 Mock
import Mock from 'mockjs'
var Mock = require('mockjs')  //生成随机数据,是以对象的形式出现
var data = Mock.mock({
    // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
    'list|1-10': [{
        // 属性 id 是一个自增数,起始值为 1,每次增 1
        'id|+1': 1
    }]
})
// 输出结果
console.log(JSON.stringify(data))    

以上代码通过node mock.js来执行

③ 拦截ajax请求

在main.js中进行引入 mock.js

Mock.mock( template )
     根据数据模板生成模拟数据
Mock.mock( rurl, template ) 
    记录数据模板。当拦截到匹配 rurl 的 Ajax 请求时,
    将根据数据模板 template 生成模拟数据,并作为响应数据返回

自行去修改data.json中的数据,即是动态的

	const appData = require("../data.json")
    const seller = appData.seller
    const goods = appData.goods
    const ratings = appData.ratings
    var Mock = require('mockjs')  
	var data = Mock.mock({
    	code:200,
    	data:{
    	 'list|1-10': [{
       		 'id|+1': 1
    		}]
    			}
})

app.vue

//发送请求
async mounted() {
	axios({
		url:"/api/seller",
		method:get
	})
	console.log(data)
}

使用mock如何实现增删改查接口,mock静态页面模拟分页,可百度查

④ 语言规范
Mock.js 的语法规范包括两部分:
- 数据模板定义规范(Data Template Definition,DTD- 数据占位符定义规范(Data Placeholder Definition,DPD

⑤ DTD

数据模板中的每个属性由 3 部分构成:属性名、生成规则、属性值
    // name:属性名    rule:生成规则   value:属性值
    'name|rule': value
注意
    属性名 和 生成规则 之间用竖线 | 分隔
    生成规则 的 含义 需要依赖 属性值的类型 才能确定
    属性值 中可以含有 @占位符
    属性值 还指定了最终值的初始值和类型
规范地址
    https://github.com/nuysoft/Mock/wiki/Syntax-Specification              

⑥ DPD

占位符 只是在属性值字符串中占个位置,并不出现在最终的属性值中。
占位符 的格式为:
    @占位符     引用Mock.Random的方法
    city:“@city”   引用Mock.Random的方法生成随机城市
var Mock = require("mockjs")
console.log(Mock.Random) @表示调用randow方法

18 练习

npm i axios 配别名api和components

拆分组件 search.vue list.vue 在app.vue中引入,为了避免命名冲突,加v-search

在stasic中引入样式,并在index.html中引入当前的样式

在src下新建api,github.js文件 配置axios实例及公共配置,拦截器 并暴露出去

search.vue 中拿输入的内容 v-model,在main.js中注册总线(提供东西为触发事件),

点击search触发总线,把username输送出去,清除输入框,清除错误提示

list.vue中接收总线,随便在哪一个生命周期内都可以created,发送请求获取username对应的所有的GitHub用户 引入githubAxios 配置params

遍历list,拿头像和数据

扩展:当头像地址和名字接口变动的时候,不改模板,用map映射
含义 需要依赖 属性值的类型 才能确定
属性值 中可以含有 @占位符
属性值 还指定了最终值的初始值和类型
规范地址
https://github.com/nuysoft/Mock/wiki/Syntax-Specification

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值