展开菜单
首页 精品内容 本月促销 装机必备 Windows macOS软件 IOS软件 Android AI PDF教程 专题
全部分类

当前位置:

首页 > 编程开发 > 现代Web通信:告别同步XHR,拥抱异步Promise

现代Web通信:告别同步XHR,拥抱异步Promise

本文旨在探讨客户端与服务器通信中同步XMLHttpRequest(XHR)的弊端及其替代方案。我们将深入分析同步XHR对用户体验的负面影响,并介绍如何通过将XHR请求封装在Promise中实现异步通信,以及使用更现代的FetchAPI来构建高效、非阻塞的Web应用,从而提升用户体验并遵循Web开发最佳实践。

现代Web客户端与服务器通信:告别同步XHR,拥抱异步与Promise

本文旨在探讨客户端与服务器通信中同步XMLHttpRequest(XHR)的弊端及其替代方案。我们将深入分析同步XHR对用户体验的负面影响,并介绍如何通过将XHR请求封装在Promise中实现异步通信,以及使用更现代的Fetch API来构建高效、非阻塞的Web应用,从而提升用户体验并遵循Web开发最佳实践。

1. 同步XMLHttpRequest的局限性与弃用

在Web开发中,客户端与服务器进行数据交互是常见的需求。传统的XMLHttpRequest(XHR)对象长期以来是实现这一目标的主要工具。然而,当XHR被配置为同步模式(即xhr.open("POST", url, false)中的第三个参数设为false)时,它会阻塞浏览器的主线程,直到请求完成并接收到响应。这意味着在请求期间,用户界面将完全冻结,无法响应任何交互,严重损害用户体验。

现代浏览器和Web标准已经明确指出,在主线程中使用同步XHR是被弃用的做法。开发者工具通常会发出警告,例如“Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user’s experience”,这不仅是建议,更是未来Web平台发展的趋势。长期来看,同步XHR可能会被完全移除,因此,迁移到异步通信模式是不可避免的。

以下是一个典型的同步XHR请求示例,它会触发上述警告:

tablink = tab.url;
$("#p1").text("Selected URL - "+tablink);
var xhr=new XMLHttpRequest();
params="url="+tablink;
var markup = "url="+tablink+"&html="+document.documentElement.innerHTML;
xhr.open("POST","http://localhost/WebExt/clientServer.php",false); // 注意这里的 'false'
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xhr.send(params);
$("#div1").text(xhr.responseText);
return xhr.responseText;

对应的服务器端PHP文件clientServer.php可能如下所示:

&1"); // 执行Python脚本
echo $decision;
?>

当执行上述JavaScript代码时,浏览器会发出同步XHR的弃用警告,并可能导致页面卡顿。

2. 异步XMLHttpRequest与Promise封装

解决同步XHR问题的核心在于采用异步通信。将XHR请求设置为异步模式(xhr.open("POST", url, true),或者省略第三个参数,因为默认就是true),可以确保请求在后台进行,不会阻塞主线程。为了更好地管理异步操作的结果,尤其是处理成功响应、错误、超时或中止等不同状态,将XHR请求封装在JavaScript的Promise对象中是一种优雅且强大的模式。

Promise对象代表一个异步操作的最终完成(或失败)及其结果值。它提供了更清晰的异步代码结构,避免了回调地狱,并支持链式调用。

以下是将异步XHR请求封装在Promise中的示例:

/**
 * 执行一个异步XMLHttpRequest请求并返回一个Promise。
 *
 * @returns {Promise} 一个Promise,解析时返回包含响应和状态的对象,
 *                            拒绝时返回包含错误信息和状态的对象。
 */
function ajaxRequest() {
    return new Promise(function(resolve, reject) {
        var xhr = new XMLHttpRequest();

        // 监听请求中止事件
        xhr.addEventListener('abort', (event) => {
            reject({'response': '', 'status': (event.currentTarget ? event.currentTarget.status : 'abort'), 'event': event});
        });
        // 监听请求错误事件
        xhr.addEventListener('error', function(event) {
            reject({'response': '', 'status': (event.currentTarget ? event.currentTarget.status : ''), 'event': event});
        });
        // 监听请求超时事件
        xhr.addEventListener('timeout', (event) => {
            reject({'response': '', 'status': (event.currentTarget ? event.currentTarget.status : 'timeout'), 'event': event});
        });
        // 监听请求加载完成事件
        xhr.addEventListener('load', function(event) {
            let response = (event.currentTarget ? event.currentTarget.response : '');

            // 根据HTTP状态码判断请求是否成功
            if (event.currentTarget && event.currentTarget.status >= 200 && event.currentTarget.status < 300) {
                resolve({'response': response, 'status': event.currentTarget.status, 'event': event});
            } else if (event.currentTarget && event.currentTarget.status >= 400 && event.currentTarget.status < 600) {
                // 服务器端错误
                reject({'response': response, 'status': event.currentTarget.status, 'event': event});
            } else {
                // 其他未知状态
                reject({'response': response, 'status': event.currentTarget.status, 'event': event});
            }
        });

        // 配置XHR请求:异步POST请求
        xhr.open("POST","http://localhost/WebExt/clientServer.php", true); // 确保是异步请求
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        // 如果需要发送数据,可以在这里设置
        // xhr.send("url=" + encodeURIComponent(tablink));
        xhr.send(); // 发送请求
    });
}

// 调用异步请求并处理结果
ajaxRequest()
    .then((result) => {
        // 请求成功,处理响应数据
        let responseElement = document.getElementById('div1'); // 假设页面中有 div1 元素
        responseElement.textContent = result.response;
        console.log("请求成功,响应内容:", result.response);
        // 可以继续执行其他操作
        console.log("hi, 请求完成后我可以做其他事情了!");
    })
    .catch((error) => {
        // 请求失败,处理错误
        console.error("请求失败:", error);
        let responseElement = document.getElementById('div1');
        responseElement.textContent = "请求失败: " + JSON.stringify(error);
    });

代码解析与注意事项:

  1. new Promise(function(resolve, reject) { ... }): 创建一个Promise实例,其构造函数接收一个执行器函数,该函数接收resolve和reject两个参数。
  2. 事件监听: 通过xhr.addEventListener监听load(请求完成)、error(网络错误)、abort(请求中止)和timeout(请求超时)等事件。
  3. resolve(value): 当异步操作成功时调用,将Promise的状态从pending变为fulfilled,并传递成功的结果。
  4. reject(reason): 当异步操作失败时调用,将Promise的状态从pending变为rejected,并传递失败的原因。
  5. HTTP状态码处理: 在load事件中,根据xhr.status(HTTP状态码)判断请求是否成功(2xx表示成功,4xx/5xx表示服务器或客户端错误)。
  6. then(): 用于处理Promise成功解析后的结果。
  7. catch(): 用于处理Promise被拒绝(即异步操作失败)后的错误。这是处理错误的首选方式。
  8. xhr.send(): 发送请求。在异步模式下,send()会立即返回,不会阻塞代码执行。

3. 更现代的替代方案:Fetch API

除了将XHR封装在Promise中,Web平台还提供了更现代、更简洁的Fetch API。Fetch API是基于Promise设计的,提供了更强大的功能和更清晰的语法,是未来进行网络请求的首选。

使用Fetch API实现上述功能会更加简洁:

tablink = tab.url;
const requestBody = "url=" + encodeURIComponent(tablink); // 编码URL参数

fetch("http://localhost/WebExt/clientServer.php", {
    method: "POST",
    headers: {
        "Content-Type": "application/x-www-form-urlencoded"
    },
    body: requestBody // 发送数据
})
.then(response => {
    // 检查响应是否成功 (HTTP 状态码 200-299)
    if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
    }
    return response.text(); // 获取响应文本
})
.then(data => {
    // 处理响应数据
    $("#div1").text(data);
    console.log("Fetch 请求成功,响应内容:", data);
})
.catch(error => {
    // 处理请求或网络错误
    console.error("Fetch 请求失败:", error);
    $("#div1").text("Fetch 请求失败: " + error.message);
});

Fetch API的优势:

  • Promise-based: 原生支持Promise,代码结构更扁平,易于理解和维护。
  • 更简洁的语法: 相比XHR,fetch的API更简洁直观。
  • 更强大的功能: 支持流式响应、Request/Response对象等。
  • 默认不发送Cookie: 默认情况下不发送跨域Cookie,安全性更高(可通过credentials选项配置)。

4. 服务器端(PHP)注意事项

无论是XHR还是Fetch,客户端发起跨域请求时,服务器端都需要配置相应的HTTP头来允许这些请求。在示例中,header("Access-Control-Allow-Origin: *"); 就是用于允许任何来源的客户端进行跨域请求。在生产环境中,通常会将其限制为特定的域名以增强安全性。

&1";
$decision=exec($command);
echo $decision;
?>

安全提示: 在PHP代码中执行外部命令(如exec("python test.py $site 2>&1"))时,务必对用户输入进行严格的验证和转义(例如使用escapeshellarg()),以防止命令注入攻击。

5. 总结与最佳实践

从同步XHR到异步XHR与Promise,再到现代的Fetch API,Web客户端与服务器通信的技术栈在不断演进。为了构建高性能、用户友好的Web应用,请遵循以下最佳实践:

  1. 始终使用异步请求: 避免在主线程中使用同步XHR,以防止阻塞UI,确保流畅的用户体验。
  2. 拥抱Promise: 利用Promise来管理异步操作的生命周期,简化回调逻辑,提升代码可读性和可维护性。
  3. 优先使用Fetch API: 对于新的网络请求,Fetch API是比XMLHttpRequest更现代、更强大的选择。
  4. 妥善处理错误: 在异步请求中,务必使用catch()或try...catch(配合async/await)来捕获和处理潜在的错误,向用户提供有意义的反馈。
  5. 理解CORS: 当客户端和服务器部署在不同域名时,确保服务器端正确配置了CORS(跨域资源共享)头。
  6. 服务器端安全: 处理来自客户端的输入时,务必进行严格的验证和清理,尤其是在执行系统命令时,以防止安全漏洞。

通过采纳这些现代的通信模式和最佳实践,开发者可以构建出更加健壮、高效且用户体验出色的Web应用程序。

本文内容来源于互联网,如有侵权请联系删除。
作者最新文章
编程开发
相关文章 更多
精品专题 更多
本月促销

正软商城本月促销专区,汇集办公、设计、安全、影音、系统工具及AI软件等正版软件优惠活动,提供限时折扣、特价授权和优惠购买信息,活动库存及价格以页面实时展示为准。

装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
灵活计算器
灵活计算器

灵活计算器是一款笔记式算数应用,支持实时计算、动态关联和云端同步功能。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

赤友清理大师
赤友清理大师

赤友清理大师是一款为 Mac 设计的智能清理优化工具,可精准扫描垃圾、大文件、重复文件等,释放磁盘空间。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

图几
图几

图几是一款适用于 macOS 的截图、标注与美化工具,支持离线操作保障隐私。界面整理和高频系统操作被放到一起考虑,桌面或窗口内容一多时,管理起来会更省心。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Menuist
Menuist

Menuist 是一款面向 macOS 的 Finder 右键菜单增强工具,主要用来补充新建文件、快捷导航等常用操作,让日常文件管理和访问路径时更高效、更顺手。

Mole
Mole

Mole 是一款专为 Mac 设计的深度清理优化工具,涵盖缓存清理、应用管理及实时状态监控等功能。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

WINDOWS 更多
Windows 10
Windows 10

Windows 10 是一款微软推出的经典操作系统,拥有硬件兼容性与多任务处理能力。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

极度公式
极度公式

极度公式是一款跨平台专业LaTeX公式识别编辑软件,支持OCR公式识别和多平台编辑。和使用说明,避免使用,享受完整功能与稳定支持。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

密码键盘
密码键盘

密码键盘是一款兼具安全性与便捷性的高效密码管理器。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

思源笔记
思源笔记

思源笔记是一款本地笔记软件,提供所见即所得的编辑方式,为长文写作带来顺滑的体验。记录、整理和输出之间的过渡会更自然,适合长期写作、做笔记或持续沉淀个人内容。

傲梅轻松备份
傲梅轻松备份

傲梅轻松备份是一款专业易用的数据备份软件,为重要数据提供安全保障。日常使用里的持续防护和信息管理会更突出,适合把安全控制放进长期使用流程中的场景。

Office 365 简体中文
Office 365 简体中文

一款文字处理软件,一种订阅式的跨平台办公软件,基于云平台提供多种服务,通过将 Excel 和 Outlook 等应用与 OneDrive 和 Microsoft Teams 等强大的云服务相结合,Office 365 可让任何人使用任何设备随时随地创建和共享内容。

Wise Folder Hider Pro
Wise Folder Hider Pro

Wise Folder Hider Pro 是一款专业级文件和文件夹隐藏加密软件,为私密数据添加多重保护。高频操作更强调就近处理,浏览、整理和跨目录移动文件时,来回切换和重复点击都会少很多。

WALTR PRO
WALTR PRO

WALTR是一款电脑至iOS文件传输转换工具,操作简单,快速实现文件识别与传送。做扫描整理、文字提取和表格转换时,它能把识别后的处理步骤接得更顺,资料录入这类场景会省下不少时间。

CodeExpander
CodeExpander

CodeExpander 是一款快捷短语输入增强工具,通过键入缩写自动展开为自定义文段,提升工作效率。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

PinStack
PinStack

PinStack是一款轻量级的Windows平台剪贴板管理工具,优化您的剪贴板使用体验。它更偏向把系统状态查看和常用调节动作放在一起,适合需要持续观察和微调设备状态的场景。

Mountain Duck
Mountain Duck

Mountain Duck 是一款能将多个网盘挂载到本地的工具,像本地磁盘一样使用网盘。清理链路的完整性会更好一些,做应用卸载、残留处理和空间整理时,通常能少走很多手动排查步骤。

Seer
Seer

Seer是一款在Win平台下的空格键功能增强效率工具,只需轻敲空格键,就能预览几乎任何格式的文件。它更适合把零散的小功能集中起来使用,处理高频琐碎任务时会更省事。

网站备案号:苏ICP备2026018738号-1 联系邮箱:bd@zhengruan.com

Copyright ©2018-2026