版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Node.js异步编程与事件驱动CONTENTS目录01异步编程基础02事件机制03定时器与执行顺序04事件循环的执行顺序05异步控制Node.js采用异步、非阻塞I/O和事件驱动模型实现高性能并发。其核心是通过事件循环(EventLoop)管理异步操作,结合回调函数、Promise、async/await等机制处理异步流程。回调函数:早期方案(如fs.readFile(callback))易导致回调地狱。Promise:链式调用优化异步流程,支持.then()和.catch()。async/await:语法糖使异步代码更易同步,需配合try/catch处理错误。事件驱动:基于EventEmitter类(如http模块),通过on()监听事件、emit()触发事件,实现解耦通信。Node.js的异步模型避免了线程阻塞,适合高并发I/O场景(如Web服务器),但需注意回调地狱和错误处理的规范性。1.异步编程基础异步编程允许代码在等待耗时操作(如网络请求、文件读写)时继续执行后续任务,而不是“干等”。回调函数是异步编程的基石,但过度嵌套会降低代码质量、引发回调地狱。后续会介绍Promise、async/await等更优雅的解决方案,以规避这一问题。1.什么是异步编程可以把程序执行类比为排队办理业务:在同步编程模式下,每个任务必须完全结束后才能开始下一个任务,就像队伍中的人必须等前面的人办完所有事项才轮到自己,在这之前只能干等(阻塞);而异步编程模式,则允许在当前任务因等待(如I/O操作)而暂停时,程序能够先去处理其他独立的任务,待原任务就绪后再继续执行,就像在购物广场的餐厅用餐时,先取号,然后逛商场,有空桌后再按照号顺序就餐。异步编程概念
1.异步编程基础2.异步编程的核心优势:非阻塞I/O计算机的I/O操作(如读写文件、网络请求)速度远慢于CPU计算速度。在同步模式下,执行到耗时操作时,代码会“卡住”,程序必须等待I/O完成才能继续,就像排队时每个人必须完全结束后才能轮到下一位。而异步编程通过“非阻塞I/O”机制,让程序在等待I/O时不阻塞后续任务执行,I/O操作完成后通过回调等方式通知结果。此方式大大提高了资源利用率,适合高并发场景。例如,浏览器同时加载多张图片,无须等一张加载完再加载下一张。3.异步编程的“甜蜜”烦恼:回调地狱异步编程需要通过“回调函数”处理任务结果,如I/O完成后需要执行的操作。但当需要顺序执行的多个异步操作任务存在依赖关系时,代码会嵌套多层回调函数,形成“回调金字塔”结构。异步编程概念
1.异步编程基础1.异步编程的“接力棒”:回调函数回调函数是异步编程的基础,本质是把函数作为参数传递给异步方法,操作完成后自动调用该函数处理结果。例如://定义回调函数functionhandleResult(err,result){if(err)console.error('出错了:',err);elseconsole.log('输出结果:',result);}//异步任务(模拟网络请求)setTimeout(handleResult,1000,null,'数据返回了!');这里的handleResult()就是回调函数,1秒后异步任务完成,会带着结果调用它。回调函数与回调地狱1.异步编程基础2.回调函数的“安全协议”:错误优先原则为了规范异步代码的错误处理,Node.js约定了“错误优先”的回调格式:回调函数的第1个参数永远是错误对象err(可能为null),第2个参数是结果。这样开发者可以统一通过if(err)先处理错误,再处理逻辑,避免漏掉关键异常。例如:fs.readFile('file.txt',(err,data)=>{if(err){console.error("读取失败:",err);//优先处理错误return;}console.log('文件内容:',data);//再处理成功逻辑});回调函数与回调地狱1.异步编程基础3.回调地狱的困境:金字塔陷阱当多个异步任务需要按顺序执行(A→B→C),且每个任务都依赖前一个的结果时,回调函数会层层嵌套,形成“嵌套过深”的问题。可读性差:代码向右缩进越来越多,像金字塔一样难以阅读。维护困难:新增一个步骤需要修改多层嵌套,牵一发而动全身。错误处理复杂:错误传递路径不清晰,难以定位具体问题。例如,假设需要“读取用户信息→根据信息查询订单→根据订单生成报表”,同步代码可能只需要3行,而异步回调代码可能变成3层嵌套,每增加一个步骤就多一层嵌套,最终导致代码难以维护。回调函数与回调地狱2.事件机制事件机制是异步编程的核心实现方式,理解事件循环的调度规则有助于写出更高效的代码,而EventEmitter提供了灵活的事件管理能力,适合模块化、解耦场景。事件循环是异步编程的底层引擎,负责调度和执行代码中的异步任务。1.事件循环:异步任务的“调度员”下面先分析以下同步任务和异步任务实例。同步任务:像厨师炒菜,必须等上一道菜做完才能做下一道(阻塞执行)。异步任务:在餐厅用餐时,点餐服务员记录客户的到店时间,先给客户一个取餐号牌,继续处理其他桌的订单,等食物做好了通知客户取餐(不阻塞执行)。事件循环就是那个“点餐服务员”,专门负责管理这些异步任务的执行顺序,让程序在等待I/O、定时器等操作完成时,可以先处理其他任务。事件循环2.事件机制2.事件循环的运行逻辑JavaScript主线程是单线程的,但能够通过事件循环实现“伪并发”。事件循环分为多个阶段(如定时器阶段、I/O回调阶段、闲置/准备阶段等),按顺序轮询执行。执行同步任务:先执行当前栈中的同步代码。处理异步任务回调:按顺序处理“已完成”的异步任务回调,如定时器到点、网络请求返回等。循环往复:不断检查是否有新的异步任务完成,直到所有任务处理完毕。3.宏任务与微任务:优先级的秘密宏任务(队列):包括定时器(setTimeout/setInterval)、I/O操作、脚本整体代码(主线程首次执行)。微任务(队列):包括Promise回调(.then()/.catch())、process.nextTick(Node.js特有)。执行规则:微任务的优先级高于宏任务的,每轮事件循环先清空所有微任务,再执行一个宏任务,保证微任务优先处理(比如Promise结果立即处理,不拖延)。事件循环2.事件机制通过事件监听和触发实现代码解耦。1.事件驱动模型:程序的“消息传递”如果客户订阅了快递通知,快递员到小区时给客户发消息(触发事件),客户看到消息后下楼取件(执行回调)。在JavaScript代码中:事件监听(on())相当于“订阅消息”,告诉程序“当X事件发生时,执行Y函数”;事件触发(emit())相当于“发送消息”,通知所有订阅者事件已发生。监听和触发事件的语法格式:emitter.on('事件名称',回调函数) //监听事件emitter.emit('事件名称',参数) //触发事件事件监听与触发2.事件机制【验证示例3-1】在文件夹Unit03中创建文件demo0301.js,在该文件中输入以下代码:constEventEmitter=require('events'); //引入事件模块constemitter=newEventEmitter(); //创建事件发射器//监听事件(订阅)emitter.on('newMessage',(msg)=>{ //事件名:newMessageconsole.log('收到消息:',msg); //回调函数});//触发事件(发消息)emitter.emit('newMessage','事件机制!'); //传递参数msg文件demo0301.js的代码执行结果如下:收到消息:事件机制!关键代码解读如下。on()可以添加多个监听器,比如同时通知手机和计算机接收消息。once()表示只监听一次,触发后自动取消订阅(类似一次性快递通知)。事件可被多次监听,触发时按注册顺序执行。未监听的错误事件会导致程序崩溃,需主动监听。事件监听与触发2.事件机制2.浏览器中的事件监听对比浏览器中用addEventListener/dispatchEvent实现事件监听,与Node.js的JavaScript代码的事件监听语法不同,但核心思想一致。示例代码://浏览器监听单击事件(订阅)button.addEventListener('click',()=>{console.log('按钮被单击了!');});//浏览器触发单击事件(模拟用户单击)button.dispatchEvent(newEvent('click'));事件监听与触发2.事件机制1.为什么需要自定义事件当需要让代码模块之间通过“事件”通信,而非直接调用函数时就需要自定义事件。例如,一个计算器模块,计算完成后通知界面更新;一个日志模块,写入文件后通知其他模块继续操作。2.自定义事件的三步法可以通过继承EventEmitter类实现自定义事件驱动对象,具体流程如下。(1)创建自定义事件类(继承EventEmitter类)。(2)监听自定义事件。(3)触发事件并传递数据。EventEmitter类的自定义事件setTimeout()与clearTimeout()
setTimeout()与clearTimeout()用于延迟执行代码,属于宏任务。其语法格式如下:consttimerId=setTimeout(回调函数,延迟时间,参数1,参数2,...);clearTimeout(timerId);//取消定时器setTimeout()用于在指定的延迟时间后执行一次回调函数。它主要接收两个参数,第一个是回调函数,第二个是延迟时间(单位为毫秒),可选参数后续可传递给回调函数。clearTimeout()则用于清除指定的定时器,阻止回调函数的执行,使用时需传入对应的定时器ID,如clearTimeout(timerId)。回调函数会被推入宏任务队列,等待事件循环调度。3.定时器与执行顺序在JavaScript中,任务分为宏任务(MacroTask)和微任务(MicroTask)。常见的宏任务包括setTimeout()、clearTimeout()、setInterval()、setImmediate()和clearlmmediate()(Node.js中)、I/O操作、UI渲染等;微任务包括Promise的then()/catch()/finally()、MutationObserver、process.nextTick()(Node.js中)等。3.定时器与执行顺序setImmediate()与clearImmediate()用于在当前事件循环的check阶段立即执行代码,属于宏任务。其语法格式如下:constimmediateId=setImmediate(回调函数);//立即执行回调函数clearImmediate(immediateId);//取消立即执行setImmediate()主要用于在当前操作的所有I/O操作完成后立即执行回调函数,它是Node.js环境中的
API,在浏览器中可能不被支持(部分浏览器有类似功能但需注意兼容性)。其语法与setTimeout()类似,接收回调函数作为第一个参数,可选参数后续可传递给回调函数,调用后返回一个定时器ID。clearImmediate()用于清除通过setImmediate()创建的定时器,传入对应的定时器ID即可。在Node.js中,setImmediate()的回调执行时机晚于process.nextTick()的回调,但早于定时器(如setTimeout()、setInterval())的回调在下一个事件循环阶段的执行。setImmediate()与clearImmediate()
3.定时器与执行顺序setImmediate()与setTimeout(0)的区别:setTimeout(()=>console.log("setTimeout"),0); //延迟0秒后执行setImmediate(()=>console.log("setImmediate")); //当前操作结束后立即执行输出顺序可能不确定,但I/O回调中setImmediate()总是优先执行。常见的应用场景:在文件读写等I/O操作后需要立即执行逻辑的场景。setImmediate()与clearImmediate()
3.定时器与执行顺序process.nextTick()将回调推入微任务队列,优先级高于所有宏任务和大部分微任务。其语法格式如下:process.nextTick(()=>{console.log("下一轮事件循环前立即执行");});执行时机:当前操作结束、下一个事件循环开始之前。process.nextTick()是Node.js特有的一个重要机制,它允许在当前操作(如事件循环的当前阶段)完成后,在下一个事件循环阶段开始前执行回调函数。也就是说,它的回调会在所有同步代码执行完毕后,立即在下一个“tick”中执行,并且优先于其他I/O事件、定时器事件等。递归调用process.nextTick()会导致事件循环阻塞(死循环)。process.nextTick()
3.定时器与执行顺序【验证示例3-3】在文件夹Unit03中创建文件demo0303.js,在该文件中输入以下代码:console.log("Start");process.nextTick(()=>console.log("NextTick"));Promise.resolve().then(()=>console.log("Promise"));console.log("End");文件demo0303.js的代码执行结果如下:StartEndNextTickPromise即输出顺序为“Start→End→NextTick→Promise”。process.nextTick()
4.事件循环的执行顺序事件循环的执行顺序大致如下:先执行同步代码,然后执行微任务队列中的所有微任务,接着执行宏任务队列中的一个宏任务,再重复这个过程。在宏任务中,不同类型的宏任务执行顺序也存在差异,在Node.js中,事件循环阶段的执行顺序如下:定时器阶段(处理setTimeout()、setInterval()回调)→I/O阶段→闲置/准备阶段→setImmediate()阶段等。而process.nextTick()回调会在当前阶段结束后、微任务开始之前执行(Node.js中微任务执行完后才会进入下一个事件循环阶段)。事件循环具体的调度规则如下。(1)微任务队列的执行顺序:process.nextTick()→Promise.then()→queueMicrotask()。所有微任务执行完后才会执行宏任务。(2)宏任务队列的执行顺序:定时器(setTimeout()/setInterval())→I/O回调→setImmediate()。每个宏任务阶段执行完毕后会再次检查微任务队列。4.事件循环的执行顺序【验证示例3-4】在文件夹Unit03中创建文件demo0304.js,在该文件中输入以下代码:setTimeout(()=>console.log("Timeout"),0);setImmediate(()=>console.log("Immediate"));process.nextTick(()=>console.log("NextTick"));Promise.resolve().then(()=>console.log("Promise"));文件demo0304.js的代码执行结果如下:NextTickPromiseTimeoutImmediate即输出顺序固定为“NextTick→Promise→Timeout→Immediate”。理解执行顺序能避免异步代码的时序错误,优化性能关键路径。Promise原理与链式调用Promise是JavaScript中处理异步操作的一种对象,它代表一个异步操作的最终完成(或失败)及其结果值。Promise有3种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。Promise一旦变为fulfilled或rejected,状态即不再改变。Promise的原理是通过回调函数的方式来处理异步操作的结果,避免了传统回调地狱的问题。创建Promise时需要传入一个执行器函数,该函数接收两个参数:resolve,用于将Promise状态从pending变为fulfilled;以及reject,用于将Promise状态从pending变为rejected。5.异步控制Promise是异步控制的基础,async/await让代码更易读。错误处理需结合场景选择try/catch或.catch(),全局监听是安全保障。始终遵循“早捕获、早处理”原则,可避免沉默失败。Promise是异步操作的容器,通过状态管理(pending→fulfilled/rejected)和链式调用解决回调地狱问题。5.异步控制链式调用是Promise的重要特性,通过then()和catch()可以实现。then()用于处理Promise成功的情况,它接收一个回调函数作为参数,该回调函数的返回值可以是一个普通值或另一个Promise对象,从而形成链式调用。catch()用于处理Promise失败的情况,等价于then(null,onRejected)。基本用法如下:constpromise=newPromise((resolve,reject)=>{//异步操作(如读取文件)if(成功)resolve(结果);elsereject(错误);});promise.then((result)=>{/*处理成功*/}).catch((err)=>{/*处理失败*/});链式调用时,每个then()返回新的Promise状态,可串联多个异步操作。Promise原理与链式调用5.异步控制【操作要求】在文件夹Unit03中,使用VSCode创建JavaScript文件case0301.js,在该文件中编写代码,使用Promise链式调用输出文本文件a.txt和b.txt中的内容。文本文件a.txt的内容为“Happylearning,efficientlearning”。文本文件b.txt的内容为“Collaborativelearning,lifelonglearning”。【实现过程】在文件夹Unit03中创建JavaScript文件case0301.js,在文件case0301.js中输入以下代码:constfs=require('fs').promises;fs.readFile('a.txt','utf8').then(data=>console.log(data)).then(data=>fs.readFile('b.txt','utf8'))//返回新的Promise状态.then(data=>console.log(data)).catch(err=>console.log("出错了:",err));文件case0301.js的代码执行结果如下:Happylearning,efficientlearningCollaborativelearning,lifelonglearning【实例3-1】使用Promise链式调用输出文本文件中的内容5.异步控制async/await是ES2017引入的语法糖,它基于Promise,代码更简洁,目的是让异步代码看起来更像同步代码,从而提高代码的可读性和可维护性。async关键字用于声明异步函数,该函数会返回一个Promise对象。await关键字只能在async函数内部使用,它后跟Promise对象,用于等待Promise执行完成,并返回其结果。如果等待的不是Promise,则会直接返回这个原始值。使用async/await可以避免链式调用,代码结构扁平化,配合try/catch错误处理更直观。async/await语法糖
5.异步控制【操作要求】在文件夹Unit03中,使用VSCode创建JavaScript文件case0302.js,在该文件中编写代码实现以下功能。(1)读取文件:使用mises.readFile()异步读取a.txt文件中的内容。(2)处理数据:将文件内容(Buffer类型)转换为UTF-8字符串,并模拟100毫秒的异步操作延迟(如API调用)。(3)结果输出:通过.then()获取处理后的文本并输出,或通过.catch()捕获可能的错误(如文件不存在)。【训练实例3-2】异步读取文件内容并进行简单处理5.异步控制【实现过程】在文件夹Unit03中创建JavaScript文件case0302.js,在文件case0302.js中输入以下代码:【训练实例3-2】异步读取文件内容并进行简单处理5.异步控制在异步编程中,错误处理至关重要,针对不同的异步模式,有不同的错误处理方式。对于Promise,可以使用catch()捕获Promise链中任何位置的错误。无论是Promise被拒绝,还是在then()的回调函数中抛出错误,都会被后续的catch()捕获。示例代码1:fetchData().then(handleSuccess).catch(err=>console.log("Promise链错误:",err));示例代码2://Promise错误处理fetch('/data').then(response=>response.json()).catch(error=>console.error('Promise链错误:',error))未被捕获的Promise错误会向外层冒泡,最终可能触发全局异常。若同时使用try/catch和catch(),优先触发最近的捕获逻辑。异步错误处理
5.异步控制对于async/await,可以使用传统的try/catch块来捕获错误。await表达式如果抛出异常(即Promise被拒绝),会被catch块捕获。示例代码1:asyncfunctionmain(){try{awaitriskyOperation();}catch(err){console.log("捕获错误:",err);}}异步错误处理
5.异步控制在JavaScript中,全局未捕获异常处理可以帮助捕获那些没有被显式处理的错误,提高应用的健壮性。全局未捕获异常处理是一种有效的“兜底”方案,防止未处理的Promise错误导致程序崩溃。在浏览器环境中,可以使用window.onerror事件和unhandledrejection事件来捕获未处理的异常。window.onerror可以捕获代码中未处理的同步错误,而unhandledrejection可以捕获未处理的Promise错误。示例代码://捕获全局未处理的同步错误window.onerror=function(message,source,lineno,colno,error){console.error('全局同步错误:',message)returntrue//阻止错误冒泡}//捕获全局未处理的Promise错误window.addEventListener('unhandledrejection',event=>{console.error('全局未处理的Promise错误:',event.reason)event.preventDefault()//阻止默认行为})全局未捕获异常处理5.异步控制在Node.js环境中,可以使用process.on('uncaughtException')捕获未处理的同步异常,使用process.on('unhandledRejection')捕获未处理的Promise错误。示例代码://捕获未处理的同步异常process.on('uncaughtException',error=>{console.error('未处理的同步异常:',error)process.exit(1)//通常建议退出进程,避免应用处于不稳定状态})//捕获未处理的Promise错误process.on('unhandledRejection',(reason,promise)=>{console.error('未处理的Promise错误:',reason)})全局未捕获异常处理4.Node.js包管理与依赖管理1.语义化版本(SemVer)(1)格式:主版本号.次版本号.修订号(如2.1.3)。(2)版本范围符号:>,大于指定版本;>=,大于等于指定版本;<,小于指定版本;<=,小于等于指定版本;~,允许修订号更新;^,允许次版本号和修订号更新;-,指定一个闭区间版本范围;*,任意版本。2.Lock文件Lock文件是协作与部署的基石。package-lock.json(npm)/yarn.lock(Yarn)精确记录安装的确切版本和依赖树结构,确保团队成员或持续集成(ContinousIntegration,CI)环境安装的依赖版本完全一致,避免因依赖版本浮动导致的问题。依赖版本控制编写JavaScript程序,通过异步任务队列控制并发执行的异步任务数量,通过限制最大并发数,避免资源过度占用,主要实现以下功能。(1)并发控制:通过concurrency参数限制同时执行的任务数量。(2)任务排队:当并发数已满时,新任务进入队列等待。(3)自动调度:当前任务完成后,自动从队列中取出下一个任务执行。任务3-1创建异步任务调度器控制异步任务的并发数量任务描述1.编写代码在文件夹Unit03中创建JavaScript文件task0301.js,在该文件中编写代码。从本书配套的教学资源中打开“实战任务3-1”对应的程序文件task0301.js,浏览相应代码。2.预期输出与执行逻辑执行文件task0301.js的代码,其预期输出如下:Task0completedTask1completedTask2completedTask3completedTask4completed使用示例的执行逻辑如下。前两个任务(0和1)立即执行(并发度=2)。任务2、3、4进入队列等待。当任务0完成后,任务2开始执行;任务1完成后,任务3开始执行,以此类推。任务3-1创建异步任务调度器控制异步任务的并发数量任务实施3.代码执行流程文件task0301.js代码执行流程如下。(1)添加任务(通过add())。将任务(函数)封装为Promise,存入队列。调用process()尝试执行队列中的任务。(2)处理任务(通过process())。检查条件:若并发队列已满或队列为空则退出。取出任务:从队列头部取出任务并执行。执行任务:增加running计数、执行任务并等待结果、通过resolve/reject返回结果。释放资源:无论成功或失败,减少running计数并递归调用process()处理下一个任务。任务3-1创建异步任务调度器控制异步任务的并发数量任务实施4.关键知识点(1)类的构造与状态管理。concurrency:最大并发数,默认值为1。running:当前正在执行的任务数。queue:待执行的任务队列,用于存储任务及其回调。(2)Promise机制。add()返回Promise,确保任务完成后可获取结果。通过resolve/reject处理任务的成功或失败。(3)异步流程控制。process()递归调用自身,实现任务的连续调度。finally确保无论任务成功或失败,都会释放并发槽位(running--)。任务3-1创建异步任务调度器控制异步任务的并发数量任务实施任务3-2实现带指数退避的异步操作重试机制任务描述为不稳定的异步操作添加重试机制,支持指数退避策略,可以有效增强程序健壮性。编写JavaScript程序,实现带指数退避的异步操作重试机制,在异步函数执行失败时自动重试,直到达到最大重试次数或成功为止。主要实现以下功能。(1)自动重试:当异步函数fn()执行失败时,自动重试指定次数(默认为3次)。(2)指数退避:每次重试前等待的时间逐渐增加(delay*(i+1)),避免立即重试导致的连续失败。(3)错误捕获:记录每次失败的错误信息,并在最终失败时抛出最后一个错误。任务3-2实现带指数退避的异步操作重试机制任务实施1.
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026网络论政面试题及答案
- 2026西安幼教面试题目及答案
- (2026年)房屋买卖居间合同(正式)
- 二手房交易买卖合同
- (2026年)商标使用授权合同
- 2026-2031年中国腕式电子血压计行业市场调查研究及发展前景预测报告
- 2025-2026学年河北省秦皇岛市青龙满族自治县数学四下期末检测模拟试题(含答案)
- 哈尔滨市依兰县公益性岗位招聘笔试真题2025
- 呼和浩特市卫生健康委员会所属事业单位招聘笔试真题2025
- 2025-2026学年江苏省连云港数学四年级下学期期中质量检测模拟试题(含答案)
- 第一至三单元质量检测卷2026-2027学年统编版语文八年级上册
- 2026年下半年幼儿园教师资格证《保教知识与能力》真题试卷
- 宁德时代笔试题及答案
- 2026年教育政策理论测试题及答案
- 中医体质辨识评估流程
- 医院基建内部控制制度(2026版)
- 护理管理前沿动态与趋势
- 主动脉夹层护理查房ppt
- MT 654-1997煤矿用带式输送机安全规范
- GB/T 531.1-2008硫化橡胶或热塑性橡胶压入硬度试验方法第1部分:邵氏硬度计法(邵尔硬度)
- GA/T 1433-2017法庭科学语音同一认定技术规范
评论
0/150
提交评论