SOURCE

/*
js中XMLHttpRequest是什么,和ajax的关系,和promise的关系?

XMLHttpRequest(XHR)是浏览器提供的一个js API,用于在后台与服务器交换数据,无需刷新整个页面
XHR的核心特点:
1.异步通信:不阻塞页面渲染
2.局部更新:只更新部分页面内容
3.跨协议:支持http、https等
4.多种数据格式:json、xml、文本等

XHR和Ajax的关系
Ajax是一种技术方案/编程模式,而XHR是实现Ajax的一种工具。

XHR与Promise的关系
XHR使用回调函数处理异步结果,容易产生回调地狱。
解决方案:Promise 封装,将XHR封装成 Promise,使代码更优雅

发展历程
2005年:XMLHttpRequest(浏览器原生API)
2006年:jQuery.ajax (封装XHR)
2015年:Fetch浏览器原生API(使用了Promise)
2016年:Axios(第三方库,基于XHR/Fetch)


Promise是ES6引入的js语言特性
Fetch API是浏览器提供的原生Web API,用于发起网络请求,返回的是Promise对象。Fetch使用Promise来处理异步操作
*/

//创建XHR对象
const xhr = new XMLHttpRequest()
//配置请求,方法,url,是否异步
xhr.open('GET','https://XXXX',true)
//设置请求头(可选)
xhr.setRequestHeader('Content-Type','application/json')
//监听状态变化
xhr.onreadystatechange = function() {
    //readyState 4表示请求完成,0未初始化,1已调用open,2已调用send,3正在接收数据
    if(xhr.readyState === 4) {
        if(xhr.statue === 200) {  //http状态码200表示成功
            console.log('成功:',xhr.responseText)
        }else {
            console.log('失败:',xhr.responseText)
        }

    }

}
xhr.send()//发送请求

//----------场景1,发送Get请求---------
function ajaxGet(url, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            callback(null, JSON.parse(xhr.responseText));
        } else if (xhr.readyState === 4) {
            callback(new Error('请求失败'), null);
        }
    };
    
    xhr.send();
}

// 使用
ajaxGet('https://api.example.com/users', (err, data) => {
    if (err) {
        console.error(err);
    } else {
        console.log(data);
    }
});

//----------场景2,发送Post请求---------
function ajaxPost(url, data, callback) {
    const xhr = new XMLHttpRequest();
    xhr.open('POST', url, true);
    xhr.setRequestHeader('Content-Type', 'application/json');
    
    xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
            callback(null, JSON.parse(xhr.responseText));
        } else if (xhr.readyState === 4) {
            callback(new Error('请求失败'), null);
        }
    };
    
    xhr.send(JSON.stringify(data));
}

// 使用
ajaxPost('https://api.example.com/users', 
    { name: '张三', age: 25 },
    (err, data) => {
        if (err) {
            console.error(err);
        } else {
            console.log('创建成功:', data);
        }
    }
);

// ----------场景3, 回调地狱示例---------
ajaxGet('/api/user', (err1, user) => {
    if (err1) return console.error(err1);
    
    ajaxGet(`/api/posts/${user.id}`, (err2, posts) => {
        if (err2) return console.error(err2);
        
        ajaxGet(`/api/comments/${posts[0].id}`, (err3, comments) => {
            if (err3) return console.error(err3);
            
            console.log(comments);
            // 嵌套太深,难以维护!
        });
    });
});

// ----------场景4,用Promise 封装解决回调地狱的问题---------
function ajax(url, options = {}) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        const method = options.method || 'GET';
        const data = options.data || null;
        
        xhr.open(method, url, true);
        
        // 设置请求头
        if (options.headers) {
            Object.keys(options.headers).forEach(key => {
                xhr.setRequestHeader(key, options.headers[key]);
            });
        }
        
        xhr.onreadystatechange = function() {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    try {
                        const response = JSON.parse(xhr.responseText);
                        resolve(response);
                    } catch (e) {
                        resolve(xhr.responseText);
                    }
                } else {
                    reject(new Error(`请求失败: ${xhr.status}`));
                }
            }
        };
        // 超时处理
        if (options.timeout) {
            xhr.timeout = options.timeout;
            xhr.ontimeout = () => reject(new Error('请求超时'));
        }
        
        // 错误处理
        xhr.onerror = () => reject(new Error('网络错误'));
        
        // 发送请求
        if (data && method === 'POST') {
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(JSON.stringify(data));
        } else {
            xhr.send();
        }
    });
}

//使用 Promise 链式调用
ajax('/api/user')
    .then(user => ajax(`/api/posts/${user.id}`))
    .then(posts => ajax(`/api/comments/${posts[0].id}`))
    .then(comments => console.log(comments))
    .catch(err => console.error(err));

//使用 async/await(更优雅)
async function fetchData() {
    try {
        const user = await ajax('/api/user');
        const posts = await ajax(`/api/posts/${user.id}`);
        const comments = await ajax(`/api/comments/${posts[0].id}`);
        console.log(comments);
    } catch (err) {
        console.error(err);
    }
}
console 命令行工具 X clear

                    
>
console