js promise的基本用法,封装axios,弄懂js事件循环机制 一文看懂

工作中promsie使用非常频繁,项目中随处可见,有使用js的事件循环机制的异步等待,封装axios的网络请求等等

目录

前言

promise 以前是为了解决回调地狱提出来的,至于回调地狱,举一个例子

一、promise的初级使用,无限链式调用(.then .catch .finally)

二、promise 可以无限链式调用的原理

三 promise实际应用

四 promise执行顺序

总结



前言

promise 以前是为了解决回调地狱提出来的,至于回调地狱,举一个例子

<script>
setTimeout(function () { 
  //第一层 等5秒打印张三在执行下一个回调函数
    console.log('张三');
     //第二层 等4秒打印李四在执行下一个回调函数
    setTimeout(function () { 
        console.log('李四');
        //第三层 等三秒打印王五
        setTimeout(function () {   
            console.log('王五');
            //第四层 等二秒打印朱六
            setTimeout(function () {   
                console.log('朱六');
                //第五层 等一秒打印老七
                setTimeout(function () {   
                    console.log("...........是不是已经很可怕了,实际业务可能还会往下嵌套")
                    console.log('老七');
                }, 1000)
            }, 2000)
        }, 3000)
    }, 4000)
}, 5000)
/** 
*输出的结果是符合预期的 张三 李四 王五 朱六 老七
*但是明显代码结构问题很大,会无限的往右延申
*/
</script>

输出的结果是符合预期的 张三 李四 王五 朱六 老七
但是明显代码结构问题很大,会无限的往右延申

 怎么样,是不是很可怕了,实际业务中,可能还会无限的往下嵌套下去,如果再{}方法块里面再写一写其他逻辑,那么整个代码会变的很难维护。

因为axios时异步的,所以很多dom操作和赋值操作,必须写在对应的函数体内,这样就会形成一个回调地狱,无限的嵌套下去。

这个时候promise登场了,对应的还有asyncawait


一、promise的初级使用,无限链式调用(.then .catch .finally)

示例:为了解决回调地狱的问题,我们看看promise的简单应用

  Promise 和Array、String 一样是内置对象可以直接使用

/**
   * Promise 和Array、String 一样是内置对象可以直接使用
   * 可以直接使用 resolve reject 来进入 .then 和 .catch
   * res 是回调接收的值 reslove 和 reject 传入的值
   */
Promise.resolve('第一层嵌套 张三').then(res =>{
  console.log(res)
  //return出去的值,是下一个回调的参数
  return '第二层嵌套 李四'
}).then(res =>{
  console.log(res)
  return '第三层嵌套 王五'
}).then(res =>{
  console.log(res)
  return '第四层嵌套 朱六'
}).then(res =>{
  console.log(res)
  return Promise.reject('第五层嵌套 老七') 
}).catch(err => {
  //catch结束promise状态 不能再继续.then
  console.log(err)
}).finally(() => {
  //无论成功失败都会执行 执行最后一次操作
  console.log('无论成功失败都会执行')
})

只要是一个promise对象,就可以再对象后面.then .catch 。then是成功的回调,catch是失败的。

看上去有没有简洁很多,虽然他还是一层包裹一层,但是不会一直再方法块里面一直嵌套下去,代码的结构看上去清晰了很多,一目了然。

你可以把我上面的代码,复制下去,再自己的控制台里运行一下。根据我写的注释,自己理解一下

二、promise 可以无限链式调用的原理

promise可以无限调用,是因为.then的时候,内部返回了一个promise对象

只要是promise对象,就可以使用.then .catch等方法

promise内部原理很复杂,我跟大家举一个简单的例子

class MyPromise{
  resolve(){

  }
  reject(){

  }
  then(){
    //执行.then方法的时候 对外返回一个promsie
    return new MyPromise()
  }
  catch(){

  }
}

在.then的时候,返回了一个promise。就类似jquery里面经典的链式调用。在调用一个方法返回一个jquery对象一样。promise内部也是如此

三 promise实际应用

代码如下(示例):最简单的列子,对axios封装套了一层promise

import axios from 'axios'
const service = axios.create({
  // baseURL: 'https://zptest-api.yocyxc.com', // url = base api url + request url
  baseURL: baseApi,
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 30000 // request timeout
})
// request拦截器 request interceptor
service.interceptors.request.use(
  async config => {
    // 请求头
    config.headers = {
      ...config.headers,
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
// respone拦截器
service.interceptors.response.use(
  response => {
    //重点,接口请求成功后,axios会返回数据,这个时候我们return一个promsie对象
    //
    return new Promise((reslove,reject) => {
      if(response.code === 200){
        reslove(response)
      }else{
        reject(response)
      }
    })
  },
  error => {
    console.log('🚀 request - error', error)
    Toast.clear()
    if (flagToast) {
      Toast(error.message)
    }
    return Promise.reject(error)
  }
)
export default service

定义一个promise对象的api接口,引入的requst就是我们封装的,在响应拦截的时候,retrun返回的是一个promsie对象,所以外面的接口调用就可以.then .catch

//上面代码封装的路径,引入进来
import request from '@/utils/request'

// 用户信息
export function userInfo(params) {
  return request({
    url: '接口地址',
    method: 'get', //请求类型
    params //传进来的参数 如果是post请求,参数为data
  })
}

 

文件里面使用,就是引入,在调用就可以,什么框架都可以

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  
</body>

<script>
  //引入我们封装的接口
  import {userInfo}  from './api/user.js'
  function getUserInfo(){
    userInfo({id:1}).then(res => {
      //userInfo是一个我们封装的promise对象
      //可以在后面进行.then 和catch
      console.log(res)
    }).catch(err => {
      console.log(err)
    })
  }
  getUserInfo()
</script>

</html>

 

四 promise执行顺序

说到执行顺序,需要先了解一个eventLoop,是一个事件循环机制

js本身是单线程,但是浏览器却不是。js是从上到下执行,遇到异步代码会放到事件队列里面,

等同步代码执行完成之后,才会执行。

  • 宏任务:promsie nextTick
  • 微任务:setTimeout setInterval

同步代码 > 宏任务 > 微任务

下面举个例子,大家就理解了

  console.log(1)
  const p = new Promise((resolve) => {
    //promise里面的代码是同步的
    console.log(2)
    //resolve出去回调是异步的
    resolve()
  })
  setTimeout(() => {
    //setTimeout是微任务,最后执行
    console.log(4)
  }, 0)
  //promsie是宏任务 优先级高于微任务的定时器 .then是异步
  p.then(() => console.log(5))
  console.log(3)

  //结果是 1 2 3 5 4

顺序是 1 2 4 5 3

执行的结果是 1 2 3 5 4

因为里面的4是微任务,最后执行,5是宏任务,在同步代码后执行

如果涉及多个微任务和宏任务,就看谁先执行。

evevtLoop类似一个对象,有两个数组,一个是宏任务,一个是微任务

遇到异步事件就往里push,然后再弹出执行


总结

  • promise对象都可以使用.then .catch
  • promise是js内置对象,还有promise.all等方法
  • promise能一直链式调用.then的原理是 .then的时候,内部返回了一个promise对象
  • promise是异步事件,会放到事件队列里,promsie是微任务,优先级高于宏任务(定时器)
  • promise的应用很多,因为有异步机制,又有类似于try () catch() 的异常捕捉,可以借住闭包和异步的特性,完成很多事情。

当然promise的知识远不止如此,promise的源码大家有兴趣可以去看看。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值