




版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第JavaScript中異步與回調(diào)的基本概念及回調(diào)地獄現(xiàn)象目錄JavaScript異步與回調(diào)一、前言二、異步函數(shù)三、回調(diào)函數(shù)四、回調(diào)的回調(diào)五、回調(diào)地獄六、總結(jié)
JavaScript異步與回調(diào)
一、前言
在學(xué)習(xí)本文內(nèi)容之前,我們必須要先了解異步的概念,首先要強(qiáng)調(diào)的是異步和并行有著本質(zhì)的區(qū)別。
并行,一般指并行計(jì)算,是說(shuō)同一時(shí)刻有多條指令同時(shí)被執(zhí)行,這些指令可能執(zhí)行于同一CPU的多核上,或者多個(gè)CPU上,或者多個(gè)物理主機(jī)甚至多個(gè)網(wǎng)絡(luò)中。同步,一般指按照預(yù)定的順序依次執(zhí)行任務(wù),只有當(dāng)上一個(gè)任務(wù)完成后,才開(kāi)始執(zhí)行下一個(gè)任務(wù)。異步,與同步相對(duì)應(yīng),異步指的是讓CPU暫時(shí)擱置當(dāng)前任務(wù),先處理下一個(gè)任務(wù),當(dāng)收到上個(gè)任務(wù)的回調(diào)通知后,再返回上個(gè)任務(wù)繼續(xù)執(zhí)行,整個(gè)過(guò)程無(wú)需第二個(gè)線程參與。
也許用圖片的方式解釋并行、同步和異步更為直觀,假設(shè)現(xiàn)在有A、B兩個(gè)任務(wù)需要處理,使用并行、同步和異步的處理方式會(huì)分別采用如下圖所示的執(zhí)行方式:
二、異步函數(shù)
JavaScript為我們提供了許多異步的函數(shù),這些函數(shù)允許我們方便的執(zhí)行異步任務(wù),也就是說(shuō),我們現(xiàn)在開(kāi)始執(zhí)行一個(gè)任務(wù)(函數(shù)),但任務(wù)會(huì)在稍后完成,具體完成時(shí)間并不清楚。
例如,setTimeout函數(shù)就是一個(gè)非常典型的異步函數(shù),此外,fs.readFile、fs.writeFile同樣也是異步函數(shù)。
我們可以自己定義一個(gè)異步任務(wù)的案例,例如自定義一個(gè)文件復(fù)制函數(shù)copyFile(from,to):
constfs=require('fs')
functioncopyFile(from,to){
fs.readFile(from,(err,data)={
if(err){
console.log(err.message)
return
fs.writeFile(to,data,(err)={
if(err){
console.log(err.message)
return
console.log('Copyfinished')
}
函數(shù)copyFile首先從參數(shù)from讀取文件數(shù)據(jù),隨后將數(shù)據(jù)寫(xiě)入?yún)?shù)to指向的文件。
我們可以像這樣調(diào)用copyFile:
copyFile('./from.txt','./to.txt')//復(fù)制文件
如果這個(gè)時(shí)候,copyFile(...)后面還有其他代碼,那么程序不會(huì)等待copyFile執(zhí)行結(jié)束,而是直接向下執(zhí)行,文件復(fù)制任務(wù)何時(shí)結(jié)束,程序并不關(guān)心。
copyFile('./from.txt','./to.txt')
//下面的代碼不會(huì)等待上面的代碼執(zhí)行結(jié)束
...
執(zhí)行到這里,好像一切還都是正常的,但是,如果我們?cè)赾opyFile(...)函數(shù)后,直接訪問(wèn)文件./to.txt中的內(nèi)容會(huì)發(fā)生什么呢?
這將不會(huì)讀到復(fù)制過(guò)來(lái)的內(nèi)容,就行這樣:
copyFile('./from.txt','./to.txt')
fs.readFile('./to.txt',(err,data)={
如果在執(zhí)行程序之前,./to.txt文件還沒(méi)有創(chuàng)建,將得到如下錯(cuò)誤:
PSE:\Code\Node\demos\03-callbacknode.\index.js
finished
Copyfinished
PSE:\Code\Node\demos\03-callbacknode.\index.js
錯(cuò)誤:ENOENT:nosuchfileordirectory,openE:\Code\Node\demos\03-callback\to.txt
Copyfinished
即使./to.txt存在,也無(wú)法讀取其中復(fù)制的內(nèi)容。
造成這種現(xiàn)象的原因是:copyFile(...)是異步執(zhí)行的,程序執(zhí)行到copyFile(...)函數(shù)后,并不會(huì)等待其復(fù)制完畢,而是直接向下執(zhí)行,從而導(dǎo)致出現(xiàn)文件./to.txt不存在的錯(cuò)誤,或者文件內(nèi)容為空錯(cuò)誤(如果提前創(chuàng)建文件)。
三、回調(diào)函數(shù)
異步函數(shù)的具體執(zhí)行結(jié)束的時(shí)間是不能確定的,例如readFile(from,to)函數(shù)的執(zhí)行結(jié)束時(shí)間大概率取決于文件from的大小。
那么,問(wèn)題在于我們?nèi)绾尾拍軠?zhǔn)確的定位copyFile執(zhí)行結(jié)束,從而讀取to文件中的內(nèi)容呢?
這就需要使用回調(diào)函數(shù),我們可以修改copyFile函數(shù)如下:
functioncopyFile(from,to,callback){
fs.readFile(from,(err,data)={
if(err){
console.log(err.message)
return
fs.writeFile(to,data,(err)={
if(err){
console.log(err.message)
return
console.log('Copyfinished')
callback()//當(dāng)復(fù)制操作完成后調(diào)用回調(diào)函數(shù)
這樣,我們?nèi)绻枰谖募?fù)制完成后,立即執(zhí)行一些操作,就可以把這些操作寫(xiě)入回調(diào)函數(shù)中:
functioncopyFile(from,to,callback){
fs.readFile(from,(err,data)={
if(err){
console.log(err.message)
return
fs.writeFile(to,data,(err)={
if(err){
console.log(err.message)
return
console.log('Copyfinished')
callback()//當(dāng)復(fù)制操作完成后調(diào)用回調(diào)函數(shù)
copyFile('./from.txt','./to.txt',function(){
//傳入一個(gè)回調(diào)函數(shù),讀取“to.txt”文件中的內(nèi)容并輸出
fs.readFile('./to.txt',(err,data)={
if(err){
console.log(err.message)
return
console.log(data.toString())
如果,你已經(jīng)準(zhǔn)備好了./from.txt文件,那么以上代碼就可以直接運(yùn)行:
PSE:\Code\Node\demos\03-callbacknode.\index.js
Copyfinished
加入社區(qū)仙宗,和我一起修仙吧
社區(qū)地址:/EKf1h
這種編程方式被稱為基于回調(diào)的異步編程風(fēng)格,異步執(zhí)行的函數(shù)應(yīng)當(dāng)提供一個(gè)回調(diào)參數(shù)用于在任務(wù)結(jié)束后調(diào)用。
這種風(fēng)格在JavaScript編程中普遍存在,例如文件讀取函數(shù)fs.readFile、fs.writeFile都是異步函數(shù)。
四、回調(diào)的回調(diào)
回調(diào)函數(shù)可以準(zhǔn)確的在異步工作完成后處理后繼事宜,如果我們需要依次執(zhí)行多個(gè)異步操作,就需要嵌套回調(diào)函數(shù)。
案例場(chǎng)景:依次讀取文件A和文件B
代碼實(shí)現(xiàn):
fs.readFile('./A.txt',(err,data)={
if(err){
console.log(err.message)
return
console.log('讀取文件A:'+data.toString())
fs.readFile('./B.txt',(err,data)={
if(err){
console.log(err.message)
return
console.log("讀取文件B:"+data.toString())
})
執(zhí)行效果:
PSE:\Code\Node\demos\03-callbacknode.\index.js
讀取文件A:仙宗無(wú)限好,只是缺了佬
讀取文件B:要想入仙宗,鏈接不能少
/H1faI
通過(guò)回調(diào)的方式,就可以在讀取文件A之后,緊接著讀取文件B。
如果我們還想在文件B之后,繼續(xù)讀取文件C呢?這就需要繼續(xù)嵌套回調(diào):
fs.readFile('./A.txt',(err,data)={//第一次回調(diào)
if(err){
console.log(err.message)
return
console.log('讀取文件A:'+data.toString())
fs.readFile('./B.txt',(err,data)={//第二次回調(diào)
if(err){
console.log(err.message)
return
console.log("讀取文件B:"+data.toString())
fs.readFile('./C.txt',(err,data)={//第三次回調(diào)
})
也就是說(shuō),如果我們想要依次執(zhí)行多個(gè)異步操作,需要多層嵌套回調(diào),這在層數(shù)較少時(shí)是行之有效的,但是當(dāng)嵌套次數(shù)過(guò)多時(shí),會(huì)出現(xiàn)一些問(wèn)題。
回調(diào)的約定
實(shí)際上,fs.readFile中的回調(diào)函數(shù)的樣式并非個(gè)例,而是JavaScript中的普遍約定。我們?nèi)蘸髸?huì)自定義大量的回調(diào)函數(shù),也需要遵守這種約定,形成良好的編碼習(xí)慣。
約定是:
callback的第一個(gè)參數(shù)是為error而保留的。一旦出現(xiàn)error,callback(err)就會(huì)被調(diào)用。第二個(gè)以及后面的參數(shù)用于接收異步操作的成功結(jié)果。此時(shí)callback(null,result1,result2,...)就會(huì)被調(diào)用。
基于以上約定,一個(gè)回調(diào)函數(shù)擁有錯(cuò)誤處理和結(jié)果接收兩個(gè)功能,例如fs.readFile(...,(err,data)={})的回調(diào)函數(shù)就遵循了這種約定。
五、回調(diào)地獄
如果我們不深究的話,基于回調(diào)的異步方法處理似乎是相當(dāng)完美的處理方式。問(wèn)題在于,如果我們有一個(gè)接一個(gè)的異步行為,那么代碼就會(huì)變成這樣:
fs.readFile('./a.txt',(err,data)={
if(err){
console.log(err.message)
return
//讀取結(jié)果操作
fs.readFile('./b.txt',(err,data)={
if(err){
console.log(err.message)
return
//讀取結(jié)果操作
fs.readFile('./c.txt',(err,data)={
if(err){
console.log(err.message)
return
//讀取結(jié)果操作
fs.readFile('./d.txt',(err,data)={
if(err){
console.log(err.message)
return
以上代碼的執(zhí)行內(nèi)容是:
讀取文件a.txt,如果沒(méi)有發(fā)生錯(cuò)誤的話;讀取文件b.txt,如果沒(méi)有發(fā)生錯(cuò)誤的話;讀取文件c.txt,如果沒(méi)有發(fā)生錯(cuò)誤的話;讀取文件d.txt,
隨著調(diào)用的增加,代碼嵌套層級(jí)越來(lái)越深,包含越來(lái)越多的條件語(yǔ)句,從而形成不斷向右縮進(jìn)的混亂代碼,難以閱讀和維護(hù)。
我們稱這種不斷向右增長(zhǎng)(向右縮進(jìn))的現(xiàn)象為回調(diào)地獄或者末日金字塔!
fs.readFile('a.txt',(err,data)={
fs.readFile('b.txt',(err,data)={
fs.readFile('c.txt',(err,data)={
fs.readFile('d.txt',(err,data)={
fs.readFile('e.txt',(err,data)={
fs.readFile('f.txt',(err,data)={
fs.readFile('g.txt',(err,data)={
fs.readFile('h.txt',(err,data)={
通往地獄的大門(mén)
===
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年智能焊接生產(chǎn)線項(xiàng)目立項(xiàng)申請(qǐng)報(bào)告范文
- 2025春季中國(guó)太平校園招聘模擬試卷及答案詳解(名師系列)
- 2025年科研項(xiàng)目規(guī)劃申請(qǐng)報(bào)告
- 安全防范工作提升承諾書(shū)7篇
- 2025福建漳州市漳浦安然招聘2人模擬試卷及完整答案詳解1套
- 經(jīng)濟(jì)可持續(xù)發(fā)展目標(biāo)推進(jìn)承諾函5篇
- 2025年湖南師范大學(xué)第一批專任教師招聘96人考前自測(cè)高頻考點(diǎn)模擬試題有完整答案詳解
- 2025年福建省中共莆田市城廂區(qū)委社會(huì)工作部招聘4人考前自測(cè)高頻考點(diǎn)模擬試題及答案詳解參考
- 房地產(chǎn)團(tuán)購(gòu)合同
- 2025安徽蕪湖宜居投資(集團(tuán))有限公司子公司人員招聘10人考前自測(cè)高頻考點(diǎn)模擬試題及答案詳解(典優(yōu))
- 2022年河北石家莊市鹿泉區(qū)司法局招聘專職人民調(diào)解員筆試備考題庫(kù)及答案解析
- 中考地理經(jīng)驗(yàn)課件
- 特殊過(guò)程確認(rèn)準(zhǔn)則
- GB/T 5599-2019機(jī)車(chē)車(chē)輛動(dòng)力學(xué)性能評(píng)定及試驗(yàn)鑒定規(guī)范
- GB/T 4937.20-2018半導(dǎo)體器件機(jī)械和氣候試驗(yàn)方法第20部分:塑封表面安裝器件耐潮濕和焊接熱綜合影響
- 【課件】高一數(shù)學(xué)《對(duì)數(shù)函數(shù)及其性質(zhì)》
- GB/T 12152-2007鍋爐用水和冷卻水中油含量的測(cè)定
- 廢紙?jiān)偕侣劶埳a(chǎn)過(guò)程及存在問(wèn)題
- FZ/T 73042-2011針織圍巾、披肩
- 優(yōu)化提升稅收營(yíng)商環(huán)境專題講座課件
- 二十四山年月日時(shí)吉兇定局
評(píng)論
0/150
提交評(píng)論