three.js 零基础到入门
three.js 零基础到入门
- 什么是 three.js
- 为什么使用 three.js
- 使用 Three.js
- 1. 创建场景
- 示例
- 2.创建相机
- 3. 创建立方体并添加网格地面
- 示例
- 5. 创建渲染器
- 示例
- 6. 添加效果(移动/雾/相机跟随物体/背景)
- 自动旋转
- 示例
- 效果
- 相机自动旋转
- 示例
- 展示效果
- 实现由远到近的雾
- 示例
- 展示效果
- Three.js 环境贴图应用
- 示例
- 展示效果
- 实现物体反光和阴影(点光源,环境光源)
- 光源
- 接受光源/投射效果(阴影)
- 示例
- 效果
- 7. 总结练习
- 控制移动思想
- 示例
- 效果
- 8. 总结知识点
什么是 three.js
Three.js
是一个用于在网页上创建和展示 3D
图形的 JavaScript
库。它简化了 WebGL
的复杂性,为开发者提供了一组易于使用的 API
,使得创建、显示和操控 3D
对象变得更加方便。以下是对 Three.js 的更详细解释:
为什么使用 three.js
解决了在前端开发中实现 3d 效果的繁琐问题
- 封装 WebGL:WebGL 是一个用于在浏览器内呈现
3D
图形的低级API
,它提供了强大的功能,但学习曲线陡峭。Three.js 封装了 WebGL 的许多复杂性,提供了更简单的接口。 - 易于使用的 API:开发者可以使用简单的函数和对象来创建和操控 3D 场景,而不需要深入理解 WebGL 的细节。
- 快速原型:由于其易用性,开发者能够快速创建和测试 3D 原型,缩短了开发周期。
使用 Three.js
1. 创建场景
在 Three.js
中,Scene
类是构建 3D
环境的基础组件。它充当所有 3D
对象(例立方体、球体、灯光、相机等)的容器,并管理这些对象的渲染。
示例
const scene = new THREE.Scene();
2.创建相机
- 在
Three.js
中,PerspectiveCamera
类用于创建透视相机,它能够模拟人眼的视角,让场景中的物体在视觉上具有深度感。透视相机是 3D 图形中常用的一种相机类型,尤其适用于展示真实世界中的场景。 - 在 Three.js 的所有类中,position 属性用于修改物体在三维空间中的坐标。通过设置 position,我们可以控制相机或其他对象在 X、Y 和 Z 轴上的位置。这使得我们能够灵活地决定视角和观察点,进而影响最终的渲染效果。通过调整相机的位置,我们可以改变观察者的视角,以便获得不同的视觉体验。
示例
const camera = new THREE.PerspectiveCamera();
camera.position.z = 10;
camera.position.y = 2;
3. 创建立方体并添加网格地面
BoxGeometry
是Three.js
中用于创建立方体的一个类。构造函数接受三个参数,分别表示立方体的宽度、高度和深度。MeshBasicMaterial
是一种材质类型,它用于定义 3D 对象的外观。与其他材质不同,MeshBasicMaterial
不受光照影响,因此它总是以定义的颜色显示,无论场景中的光照条件如何。Mesh
是Three.js
中用于创建网格的一个类。Mesh 对象结合了几何体(如 BoxGeometry)和材质(如 MeshBasicMaterial)来构建可视的 3D 物体。通过将几何体和材质结合,Mesh 表示一个具有具体形状和视觉外观的三维对象,可以在场景中进行操作和渲染。
示例
//创建立方体
const geometry = new THREE.BoxGeometry(1, 1, 1);
//设置立方体的颜色
const material = new THREE.MeshBasicMaterial({ color: 0x888 });
//创建网格并把立方体放进去
const cube = new THREE.Mesh(geometry, material);
//设置立方体的位置在可视范围内
cube.position.set(0, 3, 0);
//添加网格地面
const gridHelper = new THREE.GridHelper(10, 10);
//把立方体和网格地面加入场景中
scene.add(cube);
scene.add(gridHelper);
提示
GridHelper
是 Three.js
提供的一个辅助类,用于在场景中生成一个可视化的网格。它的主要功能是帮助开发者和设计师在 3D 空间中定位和对齐对象。GridHelper 的网格通常由线条构成,便于快速判断场景的坐标和对象的位置。
数字代表的含义:
- 第一个参数定义了网格的边长,即网格范围的大小。
- 第二个参数决定了每个维度上将网格细分为多少个单元,影响网格的密度和视觉清晰度。
5. 创建渲染器
在 Three.js
中,WebGLRenderer
是主要的渲染器,它利用 WebGL
技术来在浏览器中绘制高效的 3D
图形。
示例
const renderer = new THEE.WebGLRenderer();
//渲染到id名为container的容器里面
document.getElemnetById("container").appendChild(renderer.domElement);
//调整窗口的大小
renderer.setSize(window.innerWidth, window.innerHeight);
//刚才创建的场景和立方体放进来
renderer.render(scene, camera);
6. 添加效果(移动/雾/相机跟随物体/背景)
自动旋转
- 让立方体自动旋转,可以通过调整
Mesh
对象的rotation
属性来实现。在onMounted
中定义一个名为animate
的函数,该函数内使用requestAnimationFrame(animate)
实现持续的动画循环,并在每帧中更新
示例
const animate = () => {requestAnimationFrame(animate);cube.rotation.x += 0.01;cube.rotation.y += 0.01;//重新放进来renderer.render(scene, camera);
};animate();
效果
相机自动旋转
- 为了实现相机的自动旋转,可以使用
OrbitControls
类。该类提供了autoRotate
属性,启用此属性后,相机将自动旋转。此外,可以通过autoRotateSpeed
属性设置旋转的速度,以控制相机自转的快慢。
示例
const controls = new OrbitControls(camera, renderer.domElement);
// 对轨道控制器改变时候进行监听
controls.addEventListener("change", function () {console.log("触发change");
});// 添加阻尼
controls.enableDamping = true;
controls.dampingFactor = 0.01;// 自动旋转
controls.autoRotate = true;
controls.autoRotateSpeed = 0.5;// 进行渲染
// renderer.render(scene, camera);// 让立方体动起来
function animate() {// 告诉浏览器——你希望执行一个动画,并且要求浏览器在下次重绘之前调用指定的回调函数更新动画。该方法需要传入一个回调函数作为参数,该回调函数会在浏览器下一次重绘之前执行。requestAnimationFrame(animate);cube.rotation.x += 0.01;cube.rotation.y += 0.01;// 轨道控制器更新controls.update();renderer.render(scene, camera);
}
animate();
展示效果
实现由远到近的雾
- 为了实现 场景由远到近的雾 可以使用
Three.js
中的Fog
类来添加
示例
scene.fog = new THREE.Fog(0xcccccc, 10, 15);
展示效果
Three.js 环境贴图应用
- 使用
THREE.CubeTextureLoader
加载 6 面环境贴图 - 同时应用于场景背景和球体材质
- 实现全景天空盒+环境反射效果
示例
/*** 立方体贴图加载* 图片顺序:右(x+)、左(x-)、上(y+)、下(y-)、后(z+)、前(z-)* 注意:路径需要替换为实际资源目录*/
const cubleTExture = new THREE.CubeTextureLoader().setPath("/") // 纹理资源目录路径.load(["04.jpg","01.jpg", // 右/左"05.jpg","02.jpg", // 上/下"06.jpg","03.jpg", // 后/前]);// 将立方体贴图设置为场景背景(全景天空盒效果)
scene.background = cubleTExture;/*** 创建带环境贴图的球体* 参数说明:* SphereGeometry(半径, 宽度分段, 高度分段)* MeshBasicMaterial 基础材质支持环境贴图*/
const sphere = new THREE.SphereGeometry(1); // 单位半径的球体
const material = new THREE.MeshBasicMaterial({envMap: cubleTExture, // 材质反射环境贴图
});
scene.add(sphere); // 注:原代码中的cube应为sphere
展示效果
实现物体反光和阴影(点光源,环境光源)
受光材质
- 在
Three.js
中,有一个材质类叫MeshPhongMaterial
。该材质能够通过光源影响其外观,这意味着它适合于需要呈现高光和材质细节的场景。使用MeshPhongMaterial
时,必须为场景添加光源,以便正确地渲染出材质的反射效果和光影变化。
光源
- AmbientLight 是环境光,它接受两个参数:第一个是光的颜色,第二个是光的强度。
- PointLight 是点光源,它接受三个参数:第一个是光的颜色,第二个是光的强度,第三个是光的衰减距离(或范围)。
接受光源/投射效果(阴影)
- 在
Mesh
中 有receiveshadow
和castshadow
分别是 接受光源和投射阴影
示例
const meterial = new THREE.MeshPhongMaterial({color: 0x00ff00,shininess: 1000,
});// 创建MESH
const cubezft = new THREE.Mesh(zft, meterial);
cubezft.position.set(0, 0.5, 0);
//让物体接受光源
cubezft.receiveShadow = true;
//物体投射效果
cubezft.castShadow = true;const light = new THREE.AmbientLight(0xffffff, 1);
const lightD = new THREE.PointLight(0xffffff, 1000, 100);
lightD.position.set(5, 3, 5);
lightD.castShadow = true;
scene.add(light);
scene.add(cubezft);
//添加点光源
scene.add(lightD);
//创建地面
const meshFloor = new THREE.Mesh(//创建地面接受两个参数长宽new THREE.PlaneGeometry(20, 20),new THREE.MeshPhongMaterial({color: 0x1b5e20,side: THREE.DoubleSide, //双面都显示})
);
//设置位置
meshFloor.position.set(0, 0, -1);
//设置旋转90%
meshFloor.rotation.x -= Math.PI / 2;
//地面也要接受光源
meshFloor.receiveShadow = true;
scene.add(meshFloor);
效果
7. 总结练习
新知识
- 平移属性
translate
有三个值X
Y
Z
接受一个参数 表示平移的单位
控制移动思想
- 使用键盘侦听事件
@keyDOwn
在此事件中有一个参数 里面包含key
和keyCode
两个对象key
输出你所点击的键盘 比如我点击 a 它的值为akeyCode
的是以 ASCll码 来存储的 比如 我点击的是a
则输出 65 - 使用if判断(也可以使用switch) 判断 你点击的键盘COde值 我使用 wasd来控制前后左右移动 只要判断它对应的code值 然后 使用平移属性
translate
进行一系列的操作
如何让场景跟着移动
首先要让相机看向物体 camera.lookAt
接受三个参数 这里 我直接使用 物体的坐标传入 position
然后 让相机跟随物体 设置 相机位置实时 跟着物体 的坐标 这里我使用的是第三人称的效果 在原有物体的y轴+1 还有x轴加4 可以获得第三视角
示例
const up = (event) => {console.log(event.keyCode);console.log(event.key);if (event.key === "ArrowUp") {cubezft.translateY(0.1);} else if (event.key == "ArrowDown") {cubezft.translateY(-0.1);}else if(event.key === 'ArrowLeft'){cubezft.rotation.y +=0.1}if (event.keyCode === 65) {cubezft.translateX(-0.1);} else if (event.keyCode === 87) {cubezft.translateZ(-0.1);} else if (event.keyCode === 68) {cubezft.translateX(0.1);} else if (event.keyCode === 83) {cubezft.translateZ(0.1);}else{return}camera.lookAt(cubezft.position);camera.position.set(cubezft.position.x,cubezft.position.y + 1,cubezft.position.z + 4);
};
效果
8. 总结知识点
名称 | 属性 | 用法 |
---|---|---|
场景 | THREE.Scene() | 用于添加和管理3D物体 |
相机 | THREE.PerspectiveCamera() | 控制视图视角,实现物体观察或第一人称效果 |
坐标位置 | position | 设置物体位置,接受x、y、z三个坐标参数 |
物体旋转 | rotation | 控制物体旋转,包含x、y、z三个轴向,可接受具体角度或Math.PI值 |
立方体 | THREE.BoxGeometry() | 创建立方体,接受长、宽、高三个参数 |
圆柱体 | THREE.CylinderGeometry() | 创建圆柱体,接受四个参数依次为:顶部半径、底部半径、高度、分段数 |
圆锥 | THREE.ConeGeometry(); | 创建圆锥体。接受三个参数依次为:底部半径,高度,分段数 |
胶囊体 | THREE.CapsuleGeometry() | 创建胶囊体。接受四个参数依次为:半径、柱体长度、帽部分段数、径向分段数 |
球体 | THREE.SphereGeometry | 创建球体。接受一个参数:半径 |
纹理 | THREE.TextureLoader().load() | 加载普通纹理贴图。参数:图片路径 |
背景纹理 | THREE.CubeTextureLoader().setPath("/").load(); | 加载立方体贴图作为全景背景。参数(setPath):图片路径 、参数(load):6张图片路径数组(顺序:右左上下后前) |
自定义矩形 | THREE.PlaneGeometry() | 创建平面,接受四个参数依次为:宽度、高度、宽度分段、高度分段 |
网格 | THREE.Mesh() | 创建3D物体,参数:几何体、材质 |
Phong材质 | THREE.MeshPhongMaterial() | 创建高光材质,参数:color(颜色)、shininess(高光度) |
基础材质 | THREE.MeshBasicMaterial() | 创建不受光照影响的材质,参数:color(颜色) |
标准材质 | THREE.MeshStandardMaterial() | 创建PBR标准材质,参数:roughness(粗糙度)、metalness(金属度) |
物理材质 | THREE.MeshPhysicalMaterial() | 创建高级PBR材质,参数:clearcoat(清漆层)、transmission(透光率) |
Lambert材质 | THREE.MeshLambertMaterial() | 创建无高光的漫反射材质,参数:color(颜色) |
环境光 | THREE.AmbientLight() | 创建环境光,接受两个参数依次为:颜色、强度 |
点光源 | THREE.PointLight() | 创建点光源,接受四个参数依次为:颜色、强度、距离、衰减 |
平行光 | THREE.DirectionalLight() | 创建平行光,接受两个参数依次为:颜色、强度 |
聚光灯 | THREE.SpotLight() | 创建聚光灯,接受六个参数依次为:颜色、强度、距离、角度、衰减、半影 |
接受光源 | Mesh.receiveShadow | 设置物体是否接收阴影,布尔值 |
投射阴影 | Mesh.castShadow | 设置物体是否投射阴影,布尔值 |
使用纹理 | THREE.MeshStandardMaterial({map: texture}) | 将纹理应用到材质,参数:纹理对象 |
阴影贴图 | renderer.shadowMap.enabled = true | 启用渲染器的阴影渲染功能 |
相关文章:

three.js 零基础到入门
three.js 零基础到入门 什么是 three.js为什么使用 three.js使用 Three.js1. 创建场景示例 2.创建相机3. 创建立方体并添加网格地面示例 5. 创建渲染器示例 6. 添加效果(移动/雾/相机跟随物体/背景)自动旋转示例效果 相机自动旋转示例 展示效果 实现由远到近的雾示例展示效果 T…...

PublishSubject、ReplaySubject、BehaviorSubject、AsyncSubject的区别
python容易编辑,因此用pyrx代替rxjava3做演示会比较快捷。 pyrx安装命令: pip install rx 一、Subject(相当于 RxJava 的 PublishSubject) PublishSubject PublishSubject 将对观察者发送订阅后产生的元素,而在订阅前…...

在Ubuntu22.04 系统中安装Docker详细教程
1.更新系统软件包 #确保您的系统软件包是最新的。这有助于避免安装过程中可能遇到的问题 sudo apt update sudo apt upgrade -y2.安装必要的依赖 sudo apt install apt-transport-https ca-certificates curl software-properties-common -y3.替换软件源 echo "deb htt…...
解决transformers.adapters import AdapterConfig 报错的问题
需要安装 Adapter-Hub 的 transformers 分支,不是官方 transformers 库! pip install githttps://github.com/Adapter-Hub/transformers.git✅ 注意:这个命令会从 GitHub 下载源码并安装。你需要确保你的网络可以访问 GitHub,并且…...

AUTOSAR实战教程--DoIP_01_配置项解释
配置项 解释 备注 DoIPChannelSARef 引用DoIP Tester的源地址,就是你在DoIP Tester这个Containter中配置的Tester实例。 DoIPChannelTARef 引用目标地址。就是你在DoIPTargetAddress这个Container中的配置。 DoIPPduRRxPduId 为该pdu设置一个ID用于DoIP…...
湖北理元理律师事务所:法律视角下的债务优化与生活平衡之道
一、债务优化的本质:法律与生活的平衡艺术 债务问题常被视为单纯的财务危机,实则牵涉法律权责界定、还款能力评估、生活保障等多重维度。作为法律服务机构,我们观察到:真正的债务优化需同时满足两个条件: 法律合规性…...

机器人/智能车纯视觉巡线经典策略—滑动窗口+直方图法
作者:SkyXZ CSDN:SkyXZ~-CSDN博客 博客园:SkyXZ - 博客园 在机器人或智能车的自主导航任务中,视觉巡线是一项最为基础且关键的能力之一。通过摄像头实时获取道路图像,并基于图像信息判断行驶路径࿰…...
附加模块--Qt OpenGL模块功能及架构
一、模块功能: 主要变化 Qt OpenGL 模块的分离: 在 Qt 6 中,原来的 Qt OpenGL 功能被拆分为多个模块 传统的 Qt OpenGL 模块 (QGL*) 已被标记为废弃 新的图形架构: Qt 6 引入了基于 QRhi (Qt Rendering Hardware Interface) 的…...

503 Service Unavailable:服务器暂时无法处理请求,可能是超载或维护中如何处理?
处理 "503 Service Unavailable" 错误是服务器管理者面临的常见挑战之一。这种错误通常表示服务器暂时无法处理请求,可能是由于服务器超载、维护中或其他临时性问题导致的。在本文中,我将介绍如何处理 "503 Service Unavailable" 错…...
抖音怎么下载没有水印的视频?
你是不是经常在抖音上刷到喜欢的视频,想保存下来却总是带着烦人的水印?无论是想收藏精彩片段,还是二次创作,水印都成了“拦路虎”。别急!今天就来教你3种超简单方法,轻松下载无水印抖音视频,高清…...

虚拟机时间同步
一、常见同步方式 常见的虚拟机同步方式有给虚拟机配置ntp、或者用平台提供的agent对时与虚拟机所在的宿主机。第一种依赖网络、第二种依赖平台的agent这个三方工具。 二、利用ptp_kvm.ko来直接和宿主机同步时间 关键组件 ptp_kvm驱动、chrony。 PTP_KVM同步原理 |--------…...
三级流水线是什么?
三级流水线是什么? “三级流水线” 英文名:Three-Stage Pipeline 或 Basic 3-Stage Pipeline,是计算机处理器(CPU)设计中一种基本的指令流水线技术,它将指令的执行过程划分为三个主要阶段,使得…...

软件更新机制的测试要点与稳定性提升
💗博主介绍💗:✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 温馨提示:文末有 CSDN 平台官方提供的老师 Wechat / QQ 名片 :) Java精品实战案例《700套》 2025最新毕业设计选题推荐…...
自定义protoc-gen-go生成Go结构体,统一字段命名与JSON标签风格
背景 在日常的 Go 微服务开发中,Protocol Buffers(protobuf) 是广泛使用的数据交换格式。其配套工具 protoc-gen-go 会根据 .proto 文件生成 Go 结构体代码,但默认生成的字段名、JSON tag 命名风格往往不能满足所有团队或项目的代…...
Context API 应用与局限性
核心概念 React 的 Context API 是为了解决组件间数据共享而设计的一种机制,其核心价值在于提供了一种不通过 props 层层传递就能在组件树中共享数据的方法。在 React 应用中,数据通常是自上而下(从父组件到子组件)通过 props 传…...

LLMs 系列科普文(11)
目前我们已经介绍了大语言模型训练的两个主要阶段。第一阶段被称为预训练阶段,主要是基于互联网文档进行训练。当你用互联网文档训练一个语言模型时,得到的就是所谓的 base 模型,它本质上就是一个互联网文档模拟器,我们发现这是个…...
DQN算法(详细注释版)
DQN算法 DQN算法使用的常见问题 Q1: 为什么用目标网络而非Q网络直接计算? 答案:避免“移动目标”问题(训练中Q网络频繁变化导致目标不稳定),提高收敛性。 Q2: 为什么用 max 而不是像SARSA那样采样动作?…...
sizeof 与strlen的区别
sizeof 和 strlen 是C和C 中用于处理数据大小和字符串长度的两个不同的操作符/函数,它们的区别如下: 概念和用途 - sizeof 是一个操作符,用于计算数据类型或变量在内存中所占的字节数,它是在编译时确定的,与数据的…...
论文阅读:HySCDG生成式数据处理流程
论文地址: The Change You Want To Detect: Semantic Change Detection In Earth Observation With Hybrid Data Generation Abstract 摘要内容介绍 📌 问题背景 “Bi-temporal change detection at scale based on Very High Resolution (VHR) images is crucia…...

10万QPS高并发请求,如何防止重复下单
1. 前端拦截 首先因为是10万QPS的高并发请求,我们要保护好系统,那就是尽可能减少用户无效请求。 1.1 按钮置灰 很多用户抢票、抢购、抢红包等时候,为了提高抢中的概率,都是疯狂点击按钮。会触发多次请求,导致重复下…...

Xilinx IP 解析之 Block Memory Generator v8.4 ——02-如何配置 IP(仅 Native 接口)
相关文章: Xilinx IP 解析之 Block Memory Generator v8.4 ——01-手册重点解读(仅Native RAM) – 徐晓康的博客 Xilinx IP 解析之 Block Memory Generator v8.4 ——02-如何配置 IP(仅 Native RAM) – 徐晓康的博客 V…...

什么是高考?高考的意义是啥?
能见到这个文章的群体,应该都经历过高考,突然想起“什么是高考?意义何在?” 一、高考的定义与核心功能 **高考(普通高等学校招生全国统一考试)**是中国教育体系的核心选拔性考试,旨在为高校选拔…...
RISC-V 开发板 + Ubuntu 23.04 部署 open_vins 过程
RISC-V 开发板 Ubuntu 23.04 部署 open_vins 过程 1. 背景介绍2. 问题描述3. 解决过程3.1 卸载旧版本3.2 安装 Suitesparse v5.8.03.3 安装 Ceres Solver v2.0.03.4 解决编译爆内存问题 同步发布在个人笔记RISC-V 开发板 Ubuntu 23.04 部署 open_vins 过程 1. 背景介绍 最近…...
量子计算突破:新型超导芯片重构计算范式
2024年IBM 1281量子比特超导芯片实现0.001%量子错误率,计算速度达经典超算2.5亿倍。本文解析: 物理突破:钽基超导材料使量子相干时间突破800μs(提升15倍)架构革命:十字形…...

Spring Cloud 多机部署与负载均衡实战详解
🧱 一、引言 为什么需要多机部署? 解决单节点性能瓶颈,提升系统可用性和吞吐量 在传统单机部署模式下,系统的所有服务或应用都运行在单一服务器上。这种模式在小型项目或低并发场景中可能足够,但随着业务规模扩大、用…...

基于定制开发开源AI智能名片S2B2C商城小程序的首屏组件优化策略研究
摘要:在数字化转型背景下,用户对首屏交互效率的诉求日益提升。本文以"定制开发开源AI智能名片S2B2C商城小程序"为技术载体,结合用户行为数据与认知心理学原理,提出首屏组件动态布局模型。通过分析搜索栏、扫码入口、个人…...

EasyRTC嵌入式音视频通信SDK音视频功能驱动视频业务多场景应用
一、方案背景 随着互联网技术快速发展,视频应用成为主流内容消费方式。用户需求已从高清流畅升级为实时互动,EasyRTC作为高性能实时音视频框架,凭借低延迟、跨平台等特性,有效满足市场对多元化视频服务的需求。 二、EasyRTC技术…...
Flink 失败重试策略 :restart-strategy.type
在 Apache Flink 中,restart-strategy.type 用于指定作业的重启策略(Restart Strategy),它决定了作业在失败后如何恢复。 Flink 提供了 4 种内置重启策略,可以通过 flink-conf.yaml 或代码动态配置。 1. 可配置的 rest…...

linux下gpio控制
linux下gpio控制 文章目录 linux下gpio控制1.中断命令控制/sys/class/gpio/export终端命令控制led 2.应用程序控制 3.驱动代码控制 1.中断命令控制 通用GPIO主要用于产生输出信号和捕捉输入信号。每组GPIO均可以配置为输出输入以及特定的复用功能。 当作为输入时,内…...

Spring Boot 从Socket 到Netty网络编程(下):Netty基本开发与改进【心跳、粘包与拆包、闲置连接】
上一篇:《Spring Boot 从Socket 到Netty网络编程(上):SOCKET 基本开发(BIO)与改进(NIO)》 前言 前文中我们简单介绍了基于Socket的BIO(阻塞式)与NIO(非阻塞式࿰…...