九五至尊娱乐场网站,工业和信息化部,网络教学,网站建设模板个人目录
一、异步编程
1.1.异步编程的基本概念与重要性
1.2.事件循环#xff08;Event Loop#xff09;机制
1.3.JavaScript异步编程的常见方式及详解
示例
1.4.异步编程的最佳实践
二、跨域
2.1.什么是跨域
2.2.怎么解决跨域
1. JSONP#xff08;JSON with PaddingEvent Loop机制
1.3.JavaScript异步编程的常见方式及详解
示例
1.4.异步编程的最佳实践
二、跨域
2.1.什么是跨域
2.2.怎么解决跨域
1. JSONPJSON with Padding 2. CORSCross-Origin Resource Sharing
3. 反向代理/Nginx反向代理
4. WebSocket
5. postMessage
6. Node.js中间件代理
三、懒加载
1. 懒加载原理
2. 懒加载思路及实现
3. 图片的懒加载
案例 一、异步编程
1.1.异步编程的基本概念与重要性 异步编程是一种编程方式它允许程序在等待某些操作如网络请求、文件读取、定时器等完成的同时继续执行其他任务。这种编程方式可以显著提高程序的执行效率特别是在处理I/O密集型任务时表现出色。 在JavaScript中由于它是单线程语言即同一时间只能执行一个任务因此异步编程显得尤为重要。如果使用同步编程模型来处理需要大量时间的任务会阻塞整个线程导致页面或程序卡顿。而异步编程则可以让程序在执行这些长时间任务时继续执行其他代码从而优化用户体验。
1.2.事件循环Event Loop机制 1.事件循环Event Loop JavaScript的执行环境是单线程的这意味着它同一时间只能执行一个任务。 事件循环是JavaScript实现异步编程的核心机制。它包含一个执行栈Call Stack和一个或多个任务队列Task Queue。 执行栈用于执行同步代码而任务队列则用于存放异步任务的回调函数。 当执行栈为空时事件循环会从任务队列中取出任务并执行。 2.任务类型 宏任务Macro Task如setTimeout、setInterval、I/O操作等。 微任务Micro Task如Promise的回调、process.nextTick等。 微任务的优先级高于宏任务。在每一次事件循环中执行栈中的任务执行完毕后会先检查微任务队列执行所有微任务再执行下一个宏任务。
1.3.JavaScript异步编程的常见方式及详解 1、回调函数Callback Functions 回调函数是最早的异步处理方式。它通过将一个函数作为参数传递给另一个函数在异步任务完成后调用该函数来处理结果。 回调函数的优点是简单易懂但在处理多个异步任务时会导致回调函数嵌套过多形成“回调地狱”使代码难以维护和理解。 2、Promise对象 Promise是ES6引入的一种异步编程解决方案它是一个表示未来某个事件通常是一个异步操作的结果的对象。 Promise对象有三种状态pending进行中、fulfilled已成功和rejected已失败。状态一旦改变就不能再变。 Promise对象提供了then()和catch()方法来处理异步操作的结果和异常。then()方法用于处理成功的情况catch()方法用于处理失败的情况。 Promise支持链式调用可以避免回调地狱使代码更加简洁易读。 Promise.all()和Promise.race()是Promise对象的两个静态方法。 Promise.all()接受一个包含多个Promise的数组并返回一个新的Promise。当所有Promise都完成时这个Promise才会完成如果其中有一个Promise失败Promise.all()会立即失败。 Promise.race()则只要数组中的任意一个Promise完成或失败就会立即完成或失败。 有关promise的更详细讲解在ES6基础知识https://blog.csdn.net/m0_64455070/article/details/143714359 3、async/await async/await是基于Promise的语法糖是ES2017引入的用于处理异步代码的方式。 async用来声明一个异步函数该函数会隐式地返回一个Promise。 await只能在async函数内部使用用于等待一个Promise的完成。它返回的是Promise成功的结果值如果Promise失败则抛出异常。 async/await使得异步代码看起来像是同步的提高了代码的可读性和可维护性。它避免了回调地狱并且错误处理更加方便。 有关async/await更详细讲解在本文作者的ES6基础知识https://blog.csdn.net/m0_64455070/article/details/143714359
示例
以下是一个使用async/await实现异步网络请求的示例代码
async function fetchData(url) {try {const response await fetch(url); // 等待fetch函数的Promise完成if (!response.ok) {throw new Error(Network response was not ok);}const data await response.json(); // 等待响应的JSON数据解析完成return data;} catch (error) {console.error(Fetch error:, error);throw error; // 将错误抛出给调用者处理}
}// 使用 async/await 处理异步请求结果
(async () {try {const data await fetchData(https://api.example.com/data);console.log(Request succeeded:, data);} catch (error) {console.error(Request failed:, error);}
})();
在这个示例中fetchData函数是一个异步函数它使用await关键字等待fetch函数的Promise完成并获取响应的JSON数据。然后我们使用一个立即执行的异步函数来调用fetchData函数并处理异步请求的结果。如果请求失败则捕获异常并打印错误信息。
1.4.异步编程的最佳实践 避免回调地狱使用Promise或async/await来避免回调地狱使代码更加简洁易读。 错误处理在异步代码中添加适当的错误处理逻辑以确保程序的健壮性。 代码可读性使用有意义的函数名和变量名以及适当的注释来提高代码的可读性。 性能优化避免不必要的异步操作以减少资源消耗和提高程序性能。 二、跨域
2.1.什么是跨域 跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。在Web开发中由于同源策略Same-Origin Policy的限制浏览器默认不允许跨域请求。如果尝试进行跨域请求浏览器会抛出安全错误。 什么是同源策略
同源策略是一种安全功能它要求协议、域名和端口三者必须相同才允许访问资源。
2.2.怎么解决跨域
1. JSONPJSON with Padding
原理
JSONP是一种通过script标签实现跨域请求的技术。由于script标签不受同源策略的限制可以加载其他域的JavaScript文件。
优点
兼容性好可以解决主流浏览器的跨域问题
缺点
仅支持GET请求。
不安全可能遭受XSS攻击。
实现步骤
JSONP的工作流程如下 前端动态创建一个script标签并设置其src属性为跨域的URL同时在URL中传入一个回调函数名如callbackmyFunction。 后端服务器接收到请求后将返回的数据作为回调函数的参数并包装成JavaScript代码返回如myFunction({key:value})。 前端当浏览器加载这段JavaScript代码时会自动调用回调函数myFunction从而实现跨域数据传输。 但JSONP只能发送GET请求且存在安全风险容易受到XSS攻击。
2. CORSCross-Origin Resource Sharing
原理
CORS是一种由服务器设置响应头来允许跨域请求的机制。服务器通过设置特定的HTTP响应头如Access-Control-Allow-Origin来指定哪些域名或IP地址可以跨域访问资源。
优点
灵活可以细粒度地控制哪些源可以访问资源。
前端无需配置只需后端设置响应头。
缺点
需要服务器支持
实现步骤
前端无需特殊配置只需发送跨域请求即可。
后端服务器需要在响应头中设置Access-Control-Allow-Origin等CORS相关的头部字段。
CORS支持所有类型的HTTP请求且安全性较高是跨域请求的推荐解决方案。但需要注意的是CORS需要服务器和浏览器同时支持才能实现。
3. 反向代理/Nginx反向代理
原理
反向代理是一种在服务器端设置代理服务器将前端的跨域请求转发到目标服务器并将目标服务器的响应返回给前端的技术。Nginx是一种常见的反向代理服务器。
优点
解决跨域问题通过反向代理前端可以与目标服务器进行跨域通信而无需修改前端代码。
安全性反向代理可以作为一道安全屏障隐藏目标服务器的真实地址防止直接攻击。
负载均衡在大型应用中反向代理可以将请求分发到多个目标服务器实现负载均衡提高系统的可用性和性能。
缓存反向代理可以缓存目标服务器的响应减少对目标服务器的请求次数提高响应速度。
缺点
配置复杂性反向代理需要服务器端的配置和管理这可能需要一定的技术知识和经验。
单点故障如果反向代理服务器出现故障整个系统可能会受到影响导致服务中断。
性能瓶颈虽然反向代理可以提高性能但在高并发场景下它也可能成为性能瓶颈。 实现步骤
前端无需特殊配置只需发送请求到反向代理服务器即可。
后端需要在服务器端如Nginx配置反向代理规则将请求转发到目标服务器。
通过反向代理前端可以认为是在与同源服务器通信从而绕过浏览器的同源策略限制。但需要注意的是反向代理需要服务器端的配置和管理。
4. WebSocket
原理
WebSocket是一种在单个TCP连接上进行全双工通讯的协议。它默认支持跨域请求可以在客户端和服务器之间建立持久的连接并通过该连接进行实时数据传输。
优点
支持全双工通信实时性好。
不受同源策略限制。
缺点
需要服务器支持WebSocket协议。
可能存在性能问题如页面建立多个WebSocket连接。
实现步骤
前端使用WebSocket API如new WebSocket(ws://example.com/socket)建立连接。
后端服务器需要支持WebSocket协议并处理连接和数据传输。
WebSocket适用于需要实时通信或双向通信的场景如聊天室、实时数据监控等。
5. postMessage
原理
postMessage是HTML5中提供的一个API用于在不同窗口、标签页或iframe之间进行跨域通信。
优点
安全可以通过origin参数控制消息的来源。
支持复杂的通信场景如跨域iframe之间的通信。
缺点
需要双方配合实现。
实现步骤
前端使用window.postMessage方法发送消息到目标窗口或iframe。
接收端目标窗口或iframe需要监听message事件并处理接收到的消息。
postMessage适用于不同窗口之间的通信如父子窗口、跨域iframe等。但需要在接收端进行安全验证以防止恶意攻击。
6. Node.js中间件代理
原理
当前端发送跨域请求到Node.js服务器时Node.js服务器使用中间件拦截并处理这些请求。中间件可以检查请求的头信息、参数等并根据配置将请求转发到目标服务器。目标服务器处理请求后将响应返回给Node.js服务器Node.js服务器再将响应转发给前端。通过这种方式Node.js服务器作为中间层实现了跨域通信。常见的中间件有cors、http-proxy-middleware等。
优点
灵活性Node.js中间件代理可以灵活地处理跨域请求并与其他Node.js应用集成。
易于配置与Nginx等反向代理服务器相比Node.js中间件代理的配置通常更加简单和直观。
可扩展性Node.js中间件代理可以轻松地与其他中间件和路由集成实现更复杂的功能。
缺点
性能与Nginx等高性能反向代理服务器相比Node.js中间件代理的性能可能稍逊一筹。
资源消耗Node.js中间件代理需要额外的资源来运行和处理请求这可能会增加服务器的负载。
维护成本与Nginx等成熟的反向代理服务器相比Node.js中间件代理可能需要更多的维护和支持
实现步骤
前端发送请求到Node.js服务器。
后端Node.js服务器使用中间件拦截并处理跨域请求将请求转发到目标服务器并将响应返回给前端。
Node.js中间件代理需要服务器端的配置和管理但可以灵活地处理跨域请求并与其他Node.js应用集成。 三、懒加载
1. 懒加载原理 懒加载即按需加载或延迟加载是指当页面或应用中的某些资源如图片、视频、数据等在需要时才进行加载而不是在页面初始化时一次性加载所有资源。这种技术的核心原理是减少初始加载时间和网络流量提高页面响应速度和用户体验。
懒加载的原理主要基于以下几点
按需加载只加载用户当前需要或即将需要的资源避免加载无用资源。
异步加载将资源的加载推迟到用户需要使用时再进行不阻塞用户界面的渲染。
动态加载根据用户的行为和需求动态地生成和加载页面内容或资源。
2. 懒加载思路及实现
确定需要懒加载的资源根据页面或应用的需求确定哪些资源可以或应该进行懒加载。设置占位符在资源实际加载之前使用占位符如低分辨率图片、默认图标等来占据资源的位置。监听用户行为通过事件监听如滚动事件、点击事件等来检测用户何时需要加载资源。加载资源当用户需要资源时触发加载逻辑从服务器获取资源并替换占位符。
懒加载的实现方式有多种包括但不限于
图片懒加载通过监听滚动事件和判断图片是否进入可视区域来实现图片的延迟加载。视频懒加载在视频播放器进入用户视野或用户点击播放按钮时才开始加载视频内容。数据懒加载在用户滚动到页面底部或进行分页操作时加载更多的数据。
3. 图片的懒加载
图片的懒加载是懒加载技术中最常见的应用之一。
步骤
在HTML中为需要懒加载的图片设置占位符并使用自定义属性如data-src存储真实图片的路径。
在JavaScript中监听滚动事件判断图片是否进入可视区域。
当图片进入可视区域时将占位符替换为真实图片
// 获取页面中的所有懒加载图片
var imgs document.querySelectorAll(img[data-src]);// 监听滚动事件
window.addEventListener(scroll, function() {// 遍历所有懒加载图片imgs.forEach(function(img) {// 判断图片是否进入可视区域if (isImageInViewport(img)) {// 替换占位符为真实图片img.src img.getAttribute(data-src);// 移除data-src属性避免重复加载img.removeAttribute(data-src);}});
});// 判断图片是否进入可视区域的函数
function isImageInViewport(img) {var rect img.getBoundingClientRect();var inViewport (rect.top 0 rect.left 0 rect.bottom (window.innerHeight || document.documentElement.clientHeight) rect.right (window.innerWidth || document.documentElement.clientWidth));return inViewport;
}
现代浏览器支持
现代浏览器如Chrome、Firefox、Safari等通常支持图片的懒加载属性。可以在img标签中使用loadinglazy属性来告诉浏览器延迟加载图片直到它们出现在视口中。
例如img srcplaceholder.jpg data-srcreal-image.jpg loadinglazy altDescription
案例
1. 图片懒加载使用JavaScript和Intersection Observer API
!DOCTYPE html
html langen
head
meta charsetUTF-8
meta nameviewport contentwidthdevice-width, initial-scale1.0
titleImage Lazy Load Example/title
style.lazy-load {opacity: 0;transition: opacity 0.3s;}.lazy-load.loaded {opacity: 1;}
/style
/head
body!-- 图片列表使用 data-src 属性存储真实图片 URL --
img classlazy-load data-srcimage1.jpg altImage 1
img classlazy-load data-srcimage2.jpg altImage 2
img classlazy-load data-srcimage3.jpg altImage 3
!-- ...更多图片... --script// 获取所有需要懒加载的图片const lazyImages document.querySelectorAll(.lazy-load);// 创建 Intersection Observer 实例const observer new IntersectionObserver((entries) {entries.forEach(entry {if (entry.isIntersecting) {// 当图片进入可视区域时加载图片const img entry.target;img.src img.dataset.src;img.classList.add(loaded);// 停止观察这个图片observer.unobserve(img);}});});// 开始观察每个图片lazyImages.forEach(img {observer.observe(img);});
/script/body
/html
2. 视频懒加载使用JavaScript和事件监听
!DOCTYPE html
html langen
head
meta charsetUTF-8
meta nameviewport contentwidthdevice-width, initial-scale1.0
titleVideo Lazy Load Example/title
/head
body!-- 视频列表使用 data-src 属性存储视频 URL --
div classvideo-containervideo classlazy-load controlssource data-srcvideo1.mp4 typevideo/mp4Your browser does not support the video tag./video
/div
div classvideo-containervideo classlazy-load controlssource data-srcvideo2.mp4 typevideo/mp4Your browser does not support the video tag./video
/div
!-- ...更多视频... --script// 获取所有需要懒加载的视频const lazyVideos document.querySelectorAll(.lazy-load video);// 为每个视频容器添加点击事件监听器lazyVideos.forEach(videoContainer {const video videoContainer.querySelector(video);const source video.querySelector(source);videoContainer.addEventListener(click, () {// 当视频容器被点击时加载视频video.src source.dataset.src;video.load(); // 触发浏览器加载视频资源// 移除 data-src 属性避免重复加载source.removeAttribute(data-src);// 移除点击事件监听器避免重复操作videoContainer.removeEventListener(click, arguments.callee);});});
/script/body
/html
3. 数据懒加载使用JavaScript和滚动事件监听
!DOCTYPE html
html langen
head
meta charsetUTF-8
meta nameviewport contentwidthdevice-width, initial-scale1.0
titleData Lazy Load Example/title
style#content {max-height: 400px;overflow-y: auto;}.item {padding: 10px;border-bottom: 1px solid #ccc;}
/style
/head
bodydiv idcontent!-- 初始内容 --div classitemItem 1/divdiv classitemItem 2/div!-- ...更多初始内容... --!-- 占位符用于加载更多内容 --div idload-moreLoad More/div
/divscriptlet currentPage 1; // 当前页码// 为“加载更多”按钮添加点击事件监听器document.getElementById(load-more).addEventListener(click, () {loadMoreData(currentPage);currentPage; // 更新页码});// 滚动事件监听器当用户滚动到底部时自动加载更多数据window.addEventListener(scroll, () {const content document.getElementById(content);const loadMore document.getElementById(load-more);const bottomOfWindow window.scrollY window.innerHeight document.body.offsetHeight;const bottomOfContent content.scrollTop content.clientHeight content.scrollHeight - 10; // 减去10是为了避免因为滚动条或内容高度计算误差导致的重复加载if (bottomOfWindow || bottomOfContent) {loadMoreData(currentPage);currentPage; // 更新页码// 可以选择隐藏或禁用“加载更多”按钮直到新数据加载完成loadMore.style.display none;}});// 模拟加载更多数据的函数function loadMoreData(page) {setTimeout(() {const content document.getElementById(content);const loadMore document.getElementById(load-more);// 清除之前的占位符如果存在if (loadMore.style.display none) {loadMore.style.display block;}// 创建新的内容项并添加到页面中for (let i 0; i 5; i) {const newItem document.createElement(div);newItem.className item;newItem.textContent Item ${(page - 1) * 5 i 3}; // 假设每页加载5个项从Item 3开始content.appendChild(newItem);}}, 1000); // 模拟网络延迟设置为1秒}
/script/body
/html