从axios到promise

1,773 阅读3分钟

无论你成为谁,无论你把自己变成了什么,那就是你本来的样子。 ----《你当像鸟,飞往你的山》

请欣赏我的猫

在作为一颗螺丝钉,不停地写各种业务代码的时候,请求接口是难免的。这时候就会遇到封装HTTP请求的时候。在先人们遗留下的祖传代码中,总会遇到不同形式的封装。此时,我不禁对各式各样的封装产生了疑问,到底哪种才是最简洁多效的。于是,萌新的我在努力搜寻各大神贴之后,觉得写一个自己的总结,加深记忆。

想到前端发送http请求,最先想到的大都是axios。

Promise based HTTP client for the browser and node.js

axios用法----以get请求为例

import axios from "axios";
export default {
  data() {
    return {
      url: ""   //your url
    };
  },
  created() {
    console.log(this.get());
    console.log("created---------");
  },
  methods: {
    get() {
      return axios
        .get(this.url)
        .then(res => {
          console.log("请求接口成功");
        })
        .catch(err => {
          console.log(err);
        });
    }
  }

控制台打印的内容是:

从打印的结果中,我们可以看出,axios返回的是一个Promise对象,所以它是异步执行的。这时候我不禁想知道,Promise是个啥东东。 网络上关于promise的解析文多如牛毛,这里我就简单的说下。

Promise: 提到promise自然而然地就会跟异步联系到一起。promise的出现解决了异步执行中回调地域的出现。then方法返回的仍然是一个Promise对象,因此它可以以队列的形式解决函数多重回调的问题。

刚开始写前端的时候,接手了公司的一个项目,祖传代码中封装的http文件里层层的promise看的我云里雾里,只觉得如此复杂牛逼,一点也不敢造次改动。可是,既然axios本身就是返回的是个Promise,那为啥还要在axios请求外包上一层甚至多层的promise呢。是不是有什么玄机是我没有参透,于是就找到了下面一个问题。

有大神回复如下,忍不住点个赞!

这里穿插一下浏览器执行代码顺序。

  • 先将主任务从上至下执行
  • 再执行任务队列。任务队列中先执行微任务,再执行宏任务。
  • 微任务: 语言标准提供的叫微任务。如ES6提供的Promise 、process.nextTick
  • 宏任务:宿主环境提供的叫宏任务,如 定时器(比如:setTimeout)、事件(比如:onclick)、整体代码script
test(){
  setTimeout(() => {
    console.log("setTimeout");   //宏任务
  });
  new Promise((res, rej) => {
    res();
  }).then(res => {
    console.log("new promise");   //微任务
  });
  console.log("script");   //主流程
}
test();

执行结果:

有的时候,我们需要再拿到接口返回的数据(微任务)后,再进行其他的逻辑(主流程)处理。自Promise之后又有了Generator(生成器) 以及它的语法糖--async

  • Generator(生成器)是一类特殊的函数,由function*定义,并且,除了return语句,还可以用yield返回多次
  • Generator最大的特点就是可以交出函数的执行权(即暂停执行)
  • Promise和Generator最大的不同是,Promise只在Promise体内进行异步执行,不会阻止主任务队列。而Generator是阻断主任务队列的执行,直到异步代码执行完毕后再继续主任务队列的执行。
async test(){
  setTimeout(() => {
    console.log("setTimeout");   //宏任务
  });
  await new Promise((res, rej) => {
    res();
  }).then(res => {
    console.log("new promise");   //微任务
  });
  console.log("script");   //主流程
}
test();

执行结果如下:

以上


本该到这里就结束了,想了想还是斗胆放一下封装的http请求---手动狗头

vue-cli3

http/setBaseUrl.js

//根据环境区分域名
let rootUrl,imgUrl;
switch(process.env.NODE_ENV){
    case 'dev':
        rootUrl='http://test.mytest.cn';
        imgUrl:'http://test.oss-cn-shanghai.sliyun.com/';
        break;
    case 'pre':
        rootUrl='http://test.mytest.cn';
        imgUrl:'http://test.oss-cn-shanghai.sliyun.com/';
        break;
    case 'pro':
        rootUrl='http://test.mytest.cn';
        imgUrl:'http://test.oss-cn-shanghai.sliyun.com/';
        break;
    default:break;
}
export {rootUrl,imgUrl}

http/index.js

//可添加拦截器,请求错误处理等
import axios feom 'axios'

export default class HTTP{
    get(){
        return axios.get(url).then(response => {
            if(response.status === 200){
                return response.data
            }
        }.catch(err => {
            throw err
        })
        )
    }
    post(params){
        return axios.post(url,params).then(response => {
            if(response.status === 200){
                return response.data
            }
        }).catch((err => {
            throw err
        }))
    }
}

http/api.js

//封装api
import Http from './index'
import {rootUrl,imgUrl} from './setBaseUrl'
const apiForLogin = new (class extends Http{
    constructore(){
        super()
    }
    login(url){
    let 
        return this.get(`${rootUrl}${url}`)
    }
})
export default apiForLogin

login.vue

//调用接口
import apiForLogin from '@/http/api.js'
export dafult{
    data(){
        return {
            url:'/login'
        }
    },
    methods(){
        async login({name,password}){
            let res = await apiForLogin.login(`${url}?name=${name}&psw=${password}`)
            res.status===200 && this.$router.push('/index') 
        }
    }
}

以上以上