Promise与Axios:异步编程

发布于:2025-07-17 ⋅ 阅读:(24) ⋅ 点赞:(0)

一、解决回调嵌套/回调地狱(代码1-展示axios链式调用)

1.1 传统回调-回调地狱

如果没有Promise,我们可能需要这样写:

        axios({
            url: 'http://hmajax.itheima.net/api/province'
        }).then((provinceResult) => {
            const pname = provinceResult.data.list[0];
            console.log('省份:', pname);

            axios({
                url: 'http://hmajax.itheima.net/api/city',
                params: { pname }
            }).then((cityResult) => {
                const cname = cityResult.data.list[0];
                console.log('城市:', cname);

                axios({
                    url: 'http://hmajax.itheima.net/api/area',
                    params: { pname, cname }
                }).then((areaResult) => {
                    console.log('地区数据:', areaResult.data);
                }).catch((err) => {
                    console.error('获取地区数据失败:', err);
                });
            }).catch((err) => {
                console.error('获取城市数据失败:', err);
            });
        }).catch((err) => {
            console.error('获取省份数据失败:', err);
        });

这种"回调地狱"让代码难以阅读和维护。

而promise给了我们一种拥有较强可读性与灵活性的解决方法:
该示例为axios集成函数,其底层为promise与xhr结合使用,返回值也为promise。

let pname = ''
        axios({
            url: 'http://hmajax.itheima.net/api/province'
        }).then((result) => {
            console.log(result);
            pname = result.data.list[0]
            console.log(result.data.list[0]);
            return axios({
                url: 'http://hmajax.itheima.net/api/city',
                params: {
                    pname: `${result.data.list[0]}`
                }
            })
        }).then((result => {
            console.log(result);
            return axios({
                url: 'http://hmajax.itheima.net/api/area',
                params: {
                    pname,
                    cname: `${result.data.list[0]}`
                }
            })
        })).then(result => {
            console.log(result);

        })

1.2 链式调用实践

代码展示了典型的Promise链:

axios.get('/api/province')
  .then(result => {           // 第一个then
    pname = result.data.list[0];
    return axios.get('/api/city', {params: {pname}}); // 返回新Promise
  })
  .then(result => {           // 第二个then
    return axios.get('/api/area', {params: {pname, cname: result.data.list[0]}});
  })
  .then(result => {           // 第三个then
    console.log(result);
  });

每个then接收前一个Promise的解析值,并可以返回新Promise继续传递。
Promise通过链式调用解决了回调嵌套问题,让异步代码拥有了近乎同步代码的可读性。

二、Promise返回值详解(代码2-promise与xhr包装函数)

为了更好理解promise,我们用promise与xhr包装一个简单的axios函数:
同时为了帮助大家加强理解,尽量不使用语义化变量名

        function myaxios(lala) {
            //promise函数
            return new Promise((resolve, reject) => {
                //查询模式(有params)
                if (lala.params) {
                    //传递查询参数
                    const paramsobj = new URLSearchParams(lala.params)
                    const stree = paramsobj.toString()
                    lala.url += `?${stree}`
                }

                //配置xhr
                const xhr = new XMLHttpRequest()
                xhr.open(lala.method || 'GET', lala.url)
                xhr.addEventListener('loadend', () => {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        console.log(xhr.response);
                        console.log(JSON.parse(xhr.response));

                        resolve(JSON.parse(xhr.response))
                    }
                    else {
                        reject(new Error(xhr.response))
                    }
                })
                //请求格式(有data)
                if(lala.data){
                    xhr.setRequestHeader('Contentt-Type','application/json')
                    const streee=JSON.stringify(lala.data)
                    xhr.send(streee)
                }
                else{
                xhr.send()
            }
            })
        }
        myaxios({
            url: 'http://hmajax.itheima.net/api/register',
            method:'POST',
            data:{
                username:'evergreen',
                password:'060722'
            }
        }).then((result) => {
            console.log(result);
            console.log('注册成功');
            

        }).catch((error) => {
            console.log(error);
            
        })


2.1 核心特性

在代码2实现中,myaxios函数返回一个Promise对象:

function myaxios(lala) {
  return new Promise((resolve, reject) => {
    // 异步操作
    if(成功) resolve(result);
    else reject(error);
  });
}

关键点

  1. 每个.then()都会返回新的Promise,允许继续链式调用
  2. 回调函数的返回值决定新Promise的状态:
    • 返回普通值 → Promise resolved
    • 返回Promise → 跟随该Promise状态
    • 抛出错误 → Promise rejected

三、Axios/myaxios返回值解析

3.1 响应结构

在代码1/2中,axios/myaxios返回的Promise解析值均为一个标准响应对象:

{
  data: {},       // 服务器返回的数据(自动JSON解析)
  status: 200,    // HTTP状态码
  statusText: 'OK', 
  headers: {},    // 响应头
  config: {},     // 请求配置
  request: {}     // 底层请求对象
}

3.2 错误处理

axios自动将非2xx状态码视为reject,同时我们也在myaixios中实现:

 		if (xhr.status >= 200 && xhr.status < 300) {
            console.log(xhr.response);
            console.log(JSON.parse(xhr.response));
			resolve(JSON.parse(xhr.response))
           }
       else {
            reject(new Error(xhr.response))
           }

四、封装实践(代码2解析)

在实现自己的myaxios时,注意以下几点:

  1. Promise封装错误状态设置

    return new Promise((resolve, reject) => {
      // XHR操作
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject(new Error(xhr.response));
      }
    });
    
  2. 参数处理

    // 处理查询参数
     		  if (lala.params) {
                     //传递查询参数
                     const paramsobj = new URLSearchParams(lala.params)
                     const stree = paramsobj.toString()
                     lala.url += `?${stree}`
                 }
    // 处理请求体
     		  if(lala.data){
                     xhr.setRequestHeader('Contentt-Type','application/json')
                     const streee=JSON.stringify(lala.data)
                     xhr.send(streee)
                 }
                 else{
                 xhr.send()
    
  3. 错误对象:使用new Error()包装错误信息,在程序而非语义上标记错误信息,便于调试

完整代码:

代码1:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script>
        let pname = ''
        axios({
            url: 'http://hmajax.itheima.net/api/province'
        }).then((result) => {
            console.log(result);
            pname = result.data.list[0]
            console.log(result.data.list[0]);
            return axios({
                url: 'http://hmajax.itheima.net/api/city',
                params: {
                    pname: `${result.data.list[0]}`
                }
            })
        }).then((result => {
            console.log(result);
            return axios({
                url: 'http://hmajax.itheima.net/api/area',
                params: {
                    pname,
                    cname: `${result.data.list[0]}`
                }
            })
        })).then(result => {
            console.log(result);

        })
    </script>
</body>

</html>

代码2:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>

        /* lala={
        url:''
        method:''
        } */
       //要封装的axios
        function myaxios(lala) {
            //promise函数
            return new Promise((resolve, reject) => {
                //如果有
                if (lala.params) {
                    //传递查询参数
                    const paramsobj = new URLSearchParams(lala.params)
                    const stree = paramsobj.toString()
                    lala.url += `?${stree}`
                }

                //配置xhr
                const xhr = new XMLHttpRequest()
                xhr.open(lala.method || 'GET', lala.url)
                xhr.addEventListener('loadend', () => {
                    if (xhr.status >= 200 && xhr.status < 300) {
                        console.log(xhr.response);
                        console.log(JSON.parse(xhr.response));

                        resolve(JSON.parse(xhr.response))
                    }
                    else {
                        reject(new Error(xhr.response))
                    }
                })
                //发送xhr
                if(lala.data){
                    xhr.setRequestHeader('Contentt-Type','application/json')
                    const streee=JSON.stringify(lala.data)
                    xhr.send(streee)
                }
                else{
                xhr.send()
            }
            })
        }
        myaxios({
            url: 'http://hmajax.itheima.net/api/register',
            method:'POST',
            data:{
                username:'evergreen',
                password:'060722'
            }
        }).then((result) => {
            console.log(result);
            console.log('注册成功');
            

        }).catch((error) => {
            console.log(error);
            
        })


    </script>
</body>

</html>

网站公告

今日签到

点亮在社区的每一天
去签到