自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

JavaScript異步之從回調函數到Promise

原創(chuàng)
開發(fā) 前端
JavaScript的異步處理是前端工程師必須接觸的一塊內容。ES6在JavaScript異步的處理上引入了新的特性,使得程序員能夠更加優(yōu)雅地處理異步問題。

[[250903]]

【51CTO.com原創(chuàng)稿件】 JavaScript的異步處理是前端工程師必須接觸的一塊內容。ES6在JavaScript異步的處理上引入了新的特性,使得程序員能夠更加優(yōu)雅地處理異步問題。

若您想通過本教程直接上手Promise,那么請按順序閱讀。

若您只是想了解Promise概念,那么請直接閱讀每章的***小節(jié),等需要的時候,再回過頭來看具體的例子,從而不至于浪費您太多時間。

1.基于回調函數

1.1.異步動作與回調函數

在JavaScript中往往需要處理很多異步動作(asynchronous actions),如后臺請求某個dashboard上的顯示數據、響應一條定時信息。異步動作的執(zhí)行不會阻塞其他動作,且在執(zhí)行完成之后,由回調函數(callback)處理異步動作的結果。

假如你想載入一個JavaScript 腳本,并在腳本載入完畢之后調用一個回調函數來完成載入之后的操作。代碼片1.1-1實現(xiàn)了這樣一個異步函數loadScript。

代碼片1.1-1 

  1. //src代表JavaScript 腳本的URL,callback代表自定義回調函數 
  2. function loadScript(src, callback) { 
  3.   let script = document.createElement('script'); 
  4.   script.src = src;  
  5.   script.onload = () => callback(script);  
  6.   document.head.append(script); 
  7.  
  8.  loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => { 
  9.   alert(`Cool, the ${script.src} is loaded`); 
  10.   alert( _ ); // function declared in the loaded script 
  11. });  

***一行l(wèi)oadScript的調用可以讀作:異步函數loadScript載入腳本,并在載入執(zhí)行完畢后調用毀掉函數彈出提示框。

1.2.異步動作的順序執(zhí)行

很多場景下,往往需要依次執(zhí)行多個異步動作(上一個異步動作結束之后才能執(zhí)行下一個)。通過結合回調函數,可以寫成一個“嵌套”的異步函數,如下1.2-1。

代碼片1.2-1 

  1. loadScript('/my/script.js'function(script) {  
  2.   loadScript('/my/script2.js'function(script) {  
  3.     loadScript('/my/script3.js'function(script) { 
  4.       // ...continue after all scripts are loaded 
  5.     });  
  6.   })  
  7. });  

1.3.異步動作的異常處理

在實際場景中,還需要根據異步函數的執(zhí)行狀態(tài)(正?;蛘弋惓?來執(zhí)行不同的回調函數。代碼片1.3-1是代碼片1.1-1中的改進版本,通過增加對onerror事件的響應,異步動作拋出的異常能由用戶提供的函數來接管。此時要注意的是,這里的回調函數與前面不同,它是形式為function(error,script)的函數。

代碼片1.3-1 

  1. function loadScript(src, callback) { 
  2.   let script = document.createElement('script'); 
  3.   script.src = src; 
  4.  
  5.   script.onload = () => callback(, script); // 1 
  6.   script.onerror = () => callback(new Error(`Script load error for ${src}`)); // 2 
  7.  
  8.   document.head.append(script); 
  9.  
  10. loadScript('/my/script.js'function(error, script) { 
  11.   if (error) { 
  12.     // handle error 
  13.   } else { 
  14.     // script loaded successfully 
  15.   } 
  16. });  

這里loadScript的調用可以讀作:異步函數loadScript載入腳本,并在腳本載入執(zhí)行失敗后調用2,在腳本載入執(zhí)行成功后調用1。

1.4. 異步動作帶來的問題——惡魔金字塔

結合1.2和1.3,可以得到一個包含異常處理和多個異步動作順序執(zhí)行的例子,如代碼片1.4-1所示。

代碼片1.4-1 

  1. loadScript('1.js'function(error, script) {  
  2.   if (error) { 
  3.     handleError(error); 
  4.   } else { 
  5.     // ... 
  6.     loadScript('2.js'function(error, script) { 
  7.       if (error) { 
  8.         handleError(error); 
  9.       } else { 
  10.         // ... 
  11.         loadScript('3.js'function(error, script) { 
  12.           if (error) { 
  13.             handleError(error); 
  14.           } else { 
  15.             // ...continue after all scripts are loaded (*) 
  16.           } 
  17.         }); 
  18.  
  19.       } 
  20.     }) 
  21.   } 
  22. });  

可以看到,隨著嵌套的深入,從左往右看代碼就形成了一個金字塔結構的嵌套。這樣得到的代碼非常不利于維護和拓展,因此也被稱為惡魔金字塔(Pyramid of doom)。

代碼片1.4-2解決了惡魔金字塔的問題,但也引入了可讀性和命名空間的問題,因此不算一個優(yōu)雅的解決方案。

代碼片1.4-2 

  1. loadScript('1.js', step1);  
  2. function step1(error, script) { 
  3.   if (error) { 
  4.     handleError(error); 
  5.   } else { 
  6.     // ... 
  7.     loadScript('2.js', step2); 
  8.   } 
  9.  
  10. function step2(error, script) { 
  11.   if (error) { 
  12.     handleError(error); 
  13.   } else { 
  14.     // ... 
  15.     loadScript('3.js', step3); 
  16.   } 
  17.  
  18. function step3(error, script) { 
  19.   if (error) { 
  20.     handleError(error); 
  21.   } else { 
  22.     // ...continue after all scripts are loaded (*) 
  23.   } 
  24. };  

2.基于Promise

2.1.Promise是什么

Promise是為了解決回調函數的一些缺陷而在ES6中定義的異步解決方案,它的訂閱模式與鏈式表達式能讓開發(fā)者更加方便的定義自己的異步動作。

為了更好的理解Promise想要解決的問題,可以想象這樣一個場景:想象你是一個知名歌手,你的粉絲問你單曲發(fā)售的消息。你讓他們訂閱你的消息,這樣在你準備好專輯之后,就有專人負責通知你的粉絲,讓他們獲取關于單曲的信息,好讓他們購買專輯并推薦給身邊的朋友。

這里”歌手發(fā)布一首單曲”就是一個異步動作的生產代碼(producing code)(實際中可能是向服務器請求一條數據),“粉絲接受單曲發(fā)售的通知,然后購買專輯并推薦給身邊的朋友”,這一動作就是消費代碼(consuming code)(類似回調函數),而連接兩者的“專人”就是Promise。

Promise是一個JavaScript對象,它將生產代碼和消費代碼聯(lián)系起來,從而在生產代碼完成異步動作后,訂閱異步動作的消費代碼就能獲取結果(假如初次接觸Promise,到這至少已經理解一半了。但想了解如何使用Promise或者想閱讀Promise相關的代碼,你還得繼續(xù))。

2.2.生成一個Promise對象

根據2.1可知,Promise起到的就是“橋接”生產代碼和消費代碼的作用。Promise對象通過傳入一個執(zhí)行器(executor)執(zhí)行生產代碼,消費代碼通過.then和.catch方法訂閱結果(生產代碼的結果可能是正常的返回值也可能是一個異常)。理解了生產代碼的傳入和消費代碼如何訂閱結果,也就明白了Promise的用法。

2.2.1.生產代碼

Promise對象通過傳入一個執(zhí)行器(executor)執(zhí)行生產代碼。執(zhí)行器是形式為function(resolve, reject)的函數,它包含了異步動作的生產代碼。執(zhí)行器會在Promise對象創(chuàng)建的時候自動執(zhí)行。當執(zhí)行器執(zhí)行完成任務之后,會調用resolve(解析)來接受異步動作正常執(zhí)行完畢的結果,調用reject(拒絕)來接受一個在異步動作中拋出的異常(Error)。

這樣可能還是不夠直觀,那就看看代碼片2.2.1-1,它利用Promise改造了代碼片1.3-1。onload(表示腳本正常載入完畢)和onerror(載入過程中拋出異常)兩個異步狀態(tài)分別執(zhí)行了resolve和reject方法,分別接受一個DOM對象和Error對象。若生產代碼調用resolve解析,則Promise會把DOM對象作為結果通知給消費代碼;反之若調用reject方法,則Promise把Error對象作為結果通知給消費代碼。

代碼片2.2.1-1 

  1. function loadScript(src) { 
  2.   return new Promise(function(resolve, reject) { 
  3.     let script = document.createElement('script'); 
  4.     script.src = src; 
  5.  
  6.     script.onload = () => resolve(script); 
  7.     script.onerror = () => reject(new Error("Script load error: " + src)); 
  8.  
  9.     document.head.append(script); 
  10.   }); 
  11.  

Promise如何能夠得知一個異步狀態(tài)?這是因為Promise對象維護了兩個重要內部屬性:

  • state(狀態(tài)) :初始是“pending”,執(zhí)行完畢之后變化成“fulfilled”或者“rejected”。
  • result(結果):異步動作的結果值??梢匀我庵付?,默認是undefined。

當調用resolve時設置state為fulfilled,并把result作為參數傳給resolve;當調用reject時設置state為rejected,并把result作為參數傳給rejected。從邏輯上來看,rejected和resolve可以看做是異步動作結果的”容器”,一旦state改變,Promise就從“容器”中取出result并通知消費代碼處理。

2.2.2.消費代碼

.then和.catch方法可以使消費代碼能夠接受Promise對象發(fā)送的消息,訂閱生產代碼的結果。

2.2.2.1..then方法

.then方法的強大之處在于它的靈活性,可以定義兩個函數接受分別接受resolve和reject返回的結果。代碼片2.2.2.1-1和代碼片2.2.2.1-2分別反映了.then方法對resolve和reject結果的不同的響應。

代碼片2.2.2.1-1 

  1. let promise = new Promise(function(resolve, reject) { 
  2.   setTimeout(() => resolve("done!"), 1000); 
  3. }); 
  4.  
  5. // resolve runs the first function in .then 
  6. promise.then
  7.   result => alert(result), // shows "done!" after 1 second 
  8.   error => alert(error) // doesn't run 
  9. );  

代碼片2.2.2.1-2 

  1. let promise = new Promise(function(resolve, reject) { 
  2.   setTimeout(() => reject(new Error("Whoops!")), 1000); 
  3. }); 
  4.  
  5. // reject runs the second function in .then 
  6. promise.then
  7.   result => alert(result), // doesn't run 
  8.   error => alert(error) // shows "Error: Whoops!" after 1 second 
  9. );  

若.then方法只傳入了一個參數,那么默認消費代碼只訂閱resovle接受的結果,如代碼片2.2.2.1-3所示。

代碼片2.2.2.1-3 

  1. let promise = new Promise(resolve => { 
  2.   setTimeout(() => resolve("done!"), 1000); 
  3. }); 
  4.  
  5. promise.then(alert); // shows "done!" after 1 second  

2.2.2.2..catch方法

若消費代碼想單獨捕獲異常(訂閱異常結果),可以考慮使用.catch。.catch是.then(null,alert)的一個快捷方式。代碼片2.2.2.2-1是這兩種的實現(xiàn)方式的例子。

代碼片2.2.2.2-1 

  1. let promise = new Promise((resolve, reject) => { 
  2.   setTimeout(() => reject(new Error("Whoops!")), 1000); 
  3. }); 
  4.  
  5. // .catch(f) is the same as promise.then(null, f) 
  6. promise.catch(alert); // shows "Error: Whoops!" after 1 second 
  7.  
  8. // .catch(f) is the same as promise.then(null, f) 
  9. promise.then(,alert); // shows "Error: Whoops!" after 1 second  

2.3.使用Promise需要注意的一些細節(jié)

2.3.1.一個執(zhí)行器只會執(zhí)行一次resolve或者reject

在代碼片2.3.1-1的執(zhí)行器中,除了***個resolve之外的其他resolve或者reject都會被忽略。這兩個方法中的額外參數也會被忽略。

代碼片2.3.1-1 

  1. let promise = new Promise(function(resolve, reject) { 
  2.   resolve("done"); 
  3.  
  4.   reject(new Error("…")); // ignored 
  5.   setTimeout(() => resolve("…")); // ignored 
  6. });  

2.3.2.使用Error對象或者繼承自Error類的對象作為reject的參數

這是一個好的實踐,這樣能對異常進行更好的處理(比如針對不通的異常類型進行不同的操作)。

2.3.3.立即執(zhí)行resolve/reject

雖然在實際中,執(zhí)行器往往執(zhí)行一些異步操作,但是你也可以在執(zhí)行器中立刻執(zhí)行resolve或者reject方法,這完全沒有關系。這樣你的結果會被直接投遞到消費代碼。如代碼片2.4.3-1所示。

代碼片2.3.3-1 

  1. let promise = new Promise(function(resolve, reject) { 
  2.   // not taking our time to do the job 
  3.   resolve(123); // immediately give the result: 123 
  4. });  

2.3.4..then和.catch中定義的handler都是異步的

.then和.catch中定義的handler都是異步的,這意味著即使Promise立刻執(zhí)行了到了resolve或者reject,handler也必須等待當前的代碼執(zhí)行完畢才能被加載,如代碼片2.3.4-1所示。雖然執(zhí)行器立即執(zhí)行了resolve得到了結果,但是.then(alert)也在***被調用。如代碼片2.3.4-1所示。

代碼片2.3.4-1 

  1. // an "immediately" resolved Promise 
  2. const executor = resolve => resolve("done!"); 
  3. const promise = new Promise(executor);  
  4. promise.then(alert); // this alert shows last (*)  
  5. alert("code finished"); // this alert shows first  

3.Promise鏈

在實際中,很多時候往往需要順序執(zhí)行異步任務,但是用也帶來了”惡魔金字塔”的問題(如1.4節(jié)描述)。引入Promise鏈,我們可以優(yōu)雅的解決這個問題。

3.1.Promise鏈中的.then

多個.then方法可以構成一條Promise鏈。代碼片3.1.-1就是一個簡單的例子。

代碼片3.1.-1 

  1. new Promise(function(resolve, reject) {  
  2.   setTimeout(() => resolve(1), 1000); // (*)  
  3. }).then(function(result) { // (**)  
  4.   alert(result); // 1 
  5.   return result * 2;  
  6. }).then(function(result) { // (***)  
  7.   alert(result); // 2 
  8.   return result * 2; 
  9.  
  10. }).then(function(result) {  
  11.   alert(result); // 4 
  12.   return result * 2;  
  13. });  

執(zhí)行該代碼,結果為1——2——4,這是因為.then返回一個Promise方法,并隱式地把值賦給了Promise對象的result屬性,使得***個Promise的result屬性能夠通過調用鏈不斷傳遞。

倘若想在.then中包含異步操作,則必須返回一個包含異步對象的Promise。在處理異步操作期間,Promise鏈上的handler均不會執(zhí)行,待異步操作完成,才將結果傳遞到鏈的下一個節(jié)點。

代碼片3.1.-2 

  1. new Promise(function(resolve, reject) {  
  2.   setTimeout(() => resolve(1), 1000);  
  3. }).then(function(result) {  
  4.   alert(result); // 1  
  5.   return new Promise((resolve, reject) => { // (*) 
  6.     setTimeout(() => resolve(result * 2), 1000); 
  7.   }); 
  8.  
  9. }).then(function(result) { // (**)  
  10.   alert(result); // 2  
  11.   return new Promise((resolve, reject) => { 
  12.     setTimeout(() => resolve(result * 2), 1000); 
  13.   }); 
  14.  
  15. }).then(function(result) {  
  16.   alert(result); // 4  
  17. });  

在代碼片3.1.-2中,***的結果也是1——2——4,但是每個alter都相隔1s才會顯示??梢岳斫鉃閞eturn一個Promise阻礙了結果的傳播,必須要等這個異步動作結束,結果才能在Promise鏈中繼續(xù)傳遞。

3.2.Promise鏈中的.catch

.catch可以對Promise鏈中的異常進行處理??紤]代碼片3.2.-1。假設我們引入fetch函數(用來獲取json)獲取用戶的頭像(avatar)并顯示,.catch可以捕獲該Promise鏈中拋出的異常。

代碼片3.2.-1 

  1. fetch('/article/promise-chaining/user.json'
  2.   .then(response => response.json()) 
  3.   .then(user => fetch(`https://api.github.com/users/${user.name}`)) 
  4.   .then(response => response.json()) 
  5.   .then(githubUser => new Promise(function(resolve, reject) { 
  6.     let img = document.createElement('img'); 
  7.     img.src = githubUser.avatar_url; 
  8.     img.className = "promise-avatar-example"
  9.     document.body.append(img); 
  10.  
  11.     setTimeout(() => { 
  12.       img.remove(); 
  13.       resolve(githubUser); 
  14.     }, 3000); 
  15.   })) 
  16.   .catch(error => alert(error.message));  

但是這樣還不夠好,在實際編碼中,常常需要在代碼中拋出異常,并根據異常的類型來做相應的處理。幸運的是,Promise鏈默認把在處理鏈中拋出的異常當reject進行處理,并讓用戶用.catch捕獲。如代碼片3.2.-2所示,loadJson函數在Promise鏈中會檢測HTTP的狀態(tài)碼,若不為200(不成功),就拋出自定義異常“new HttpError(response)”,并被catch所捕獲。

代碼片3.2.-2 

  1. class HttpError extends Error { // (1) 
  2.   constructor(response) { 
  3.     super(`${response.status} for ${response.url}`); 
  4.     this.name = 'HttpError'
  5.     this.response = response; 
  6.   } 
  7.  
  8. function loadJson(url) { // (2) 
  9.   return fetch(url) 
  10.     .then(response => { 
  11.       if (response.status == 200) { 
  12.         return response.json(); 
  13.       } else { 
  14.         throw new HttpError(response); 
  15.       } 
  16.     }) 
  17.  
  18. loadJson('no-such-user.json') // (3) 
  19.   .catch(alert); // HttpError: 404 for .../no-such-user.json  

3.3.重新拋出異常及未處理異常

在一般的try…catch…結構中,若一個異常無法處理,往往可以重新拋出(Rethrowing)給上一級的異常處理函數處理。Promise鏈也支持這種形式。在Promis中也可以重新拋出異常,并被最近一個.catch所捕獲。

考慮代碼片3.3.-1。在Promise對象拋出一個異常”Whoops!”之后,這個Promise對象的狀態(tài)變?yōu)榫芙^(reject),鏈上最近的一個.catch方法被調用,并判斷是否是URI異常,顯然”Whoops!”不屬于這類異常,因此顯示”Can’t handle such error”,并重新拋出異常。該異常被鏈上的第二個.catch所捕獲,最終顯示”The unknown error has occurred: Error: Whoops!”。

代碼片3.3.-1 

  1. // the execution: catch -> catch -> then 
  2. new Promise(function(resolve, reject) { 
  3.  
  4.   throw new Error("Whoops!"); 
  5.  
  6. }).catch(function(error) { // (*) 
  7.  
  8.   if (error instanceof URIError) { 
  9.     // handle it 
  10.   } else { 
  11.     alert("Can't handle such error"); 
  12.  
  13.     throw error; // throwing this or another error jumps to the next catch 
  14.   } 
  15.  
  16. }).then(function() { 
  17.   /* never runs here */ 
  18. }).catch(error => { // (**) 
  19.  
  20.   alert(`The unknown error has occurred: ${error}`); 
  21.   // don't return anything => execution goes the normal way 
  22.  
  23. });  

一般來說Promise鏈底部寫上.catch來捕獲異常是一個非常好的習慣。假如不這樣做,那么javaScript引擎會捕獲該異常并在控制臺顯示 。當然,也可以在瀏覽器中可以通過注冊一個unhandledrejection事件(unhandledrejection事件是HTML標準的一部分)監(jiān)聽器,來捕獲未處理異常,如代碼片3.3.-2所示:

代碼片3.3.-2 

  1. window.addEventListener('unhandledrejection'function(event) { 
  2.   // the event object has two special properties: 
  3.   alert(event.promise); // [object Promise] - the promise that generated the error 
  4.   alert(event.reason); // Error: Whoops! - the unhandled error object 
  5. }); 
  6.  
  7. new Promise(function() { 
  8.   throw new Error("Whoops!"); 
  9. }); // no catch to handle the er  

4.Promise API

Promise對象有四個靜態(tài)方法:resolve/reject/all/race,可以在某些場景下讓處理Promise對象的代碼變得更加簡潔。

4.1.Promise.resolve/Promise.reject

Promise.resolve/Promise.reject直接返回一個已經被resolve/reject的Promise對象。代碼片4.1-1和代碼片4.1-2分別顯示了Promise.resolve和Promise.reject的等價形式。值得注意的是,Promise.resolve/Promise.reject返回的是Promise對象,因此也可用.then/.catch構成Promise鏈。

代碼片4.1-1 

  1. let promise = Promise.resolve(value); 
  2. let promise = new Promise(resolve => resolve(value)); 
  3. 代碼片4.1-2  

代碼片4.1-2 

  1. let promise = Promise.reject(error);  
  2. let promise = new Promise((resolve, reject) => reject(error));  

4.2.Promise.all

Promise.all接受一個可迭代對象(往往是Promise數組)作為輸入,并行地執(zhí)行它們,等待所有Promise執(zhí)行完畢之后返回一個Promise對象。這個Promise對象的result屬性是包含所有對應結果的一個數組,如代碼片4.2-1所示。

代碼片4.2-1 

  1. Promise.all([ 
  2.   new Promise((resolve, reject) => setTimeout(() => resolve(1), 3000)), // 1 
  3.   new Promise((resolve, reject) => setTimeout(() => resolve(2), 2000)), // 2 
  4.   new Promise((resolve, reject) => setTimeout(() => resolve(3), 1000))  // 3 
  5. ]).then(alert); // 1,2,3 when promises are ready: each promise contributes an array member  

需要指出的是,當傳入的可迭代對象中包含非Promise對象的元素時,Promise.all會自動調用Promise.resolve方法將其包裝成一個Promise對象并返回。如代碼片4.2-2所示。

代碼片4.2-2 

  1. Promise.all([ 
  2.   new Promise((resolve, reject) => { 
  3.     setTimeout(() => resolve(1), 1000) 
  4.   }), 
  5.   2, // treated as Promise.resolve(2) 
  6.   3  // treated as Promise.resolve(3) 
  7. ]).then(alert); // 1, 2, 3  

4.3.Promise.race

Promise.race接受一個可迭代對象(往往是Promise數組)作為輸入,并行地執(zhí)行它們,將***個返回的Promise對象作為結果,如代碼片4.3-1所示。***alter的結果是1

代碼片4.3-1 

  1. Promise.race([ 
  2.   new Promise((resolve, reject) => setTimeout(() => resolve(1), 1000)), 
  3.   new Promise((resolve, reject) => setTimeout(() => reject(new Error("Whoops!")), 2000)), 
  4.   new Promise((resolve, reject) => setTimeout(() => resolve(3), 3000)) 
  5. ]).then(alert); // 1  

5.async/await

假如你是按順序讀完,那么到這里理解async/await關鍵字就非常容易。async/await關鍵字作為語法糖,能讓操作Promise的代碼更加簡潔可讀。

5.1.async

async關鍵詞置于你想修飾的函數前,可以將一個非Promise的結果通過Promise.resolve的封裝變成一個Promise對象,如代碼片5.1-1所示。

代碼片5.1-1 

  1. async function f() { 
  2.   return 1; 
  3.  
  4. f().then(alert); // 1 
  5. 5.2.await  

5.2.await

await的作用和.then非常相似,用來等待一個Promise對象的異步返回。await和async密不可分,await必須在async修飾的函數中才能使用。如代碼片5.2-1所示。

代碼片5.2-1 

  1. async function f() { 
  2.  
  3.   let promise = new Promise((resolve, reject) => { 
  4.     setTimeout(() => resolve("done!"), 1000) 
  5.   }); 
  6.  
  7.   let result = await promise; // wait till the promise resolves (*) 
  8.  
  9.   alert(result); // "done!" 
  10.  
  11. f();  

值得注意的是,一旦使用await,就可以使用try…catch來捕獲異常。相比.catch來說,這樣捕獲異常更加方便。

代碼片5.2-2 

  1. async function f() { 
  2.  
  3.   try { 
  4.     let response = await fetch('http://no-such-url'); 
  5.   } catch(err) { 
  6.     alert(err); // TypeError: failed to fetch 
  7.   } 
  8.  
  9. f();  

6.總結

本文參考在線教程并根據個人的實踐經驗有側重的總結了一下ES6的異步特性:Promise概念、基本用法、靜態(tài)方法以及兩個關鍵字async和await。這里沒有提到的是,Promise仍然有著一些缺點,比如它無法像RxJS一般很好地處理流事件。和所有的教程一樣,本文不可能涵蓋到異步編程的所有細節(jié),但是若能對你有所啟發(fā),那就是再好不過了。

7. 參考鏈接

8.作者簡介

邱仁博,多年運營商商業(yè)分析、數據中心數據庫方向工作經驗,現(xiàn)任職于某地市事業(yè)單位信息技術部。日常關注國內外極客新聞、前后端技術。海外知識搬運工。

【51CTO原創(chuàng)稿件,合作站點轉載請注明原文作者和出處為51CTO.com】

 

責任編輯:龐桂玉 來源: 51CTO
相關推薦

2017-05-11 20:20:59

JavascriptPromiseWeb

2021-06-07 09:44:10

JavaScript開發(fā)代碼

2019-11-05 10:03:08

callback回調函數javascript

2021-12-10 07:47:30

Javascript異步編程

2025-03-24 07:20:00

2021-01-14 07:52:24

JavaScript回調函數

2021-06-06 19:51:07

JavaScript異步編程

2017-08-28 15:21:29

異步處理回調函數異步編程

2009-08-21 17:02:20

ASP.NET異步回調

2015-10-26 09:25:42

2023-06-29 07:48:35

異步加載JavaScript

2016-09-18 21:14:54

JavascriptPromiseWeb

2023-11-08 13:18:00

JestJavaScript框架

2012-02-01 10:33:59

Java

2022-01-04 20:52:50

函數異步Promise

2009-11-09 15:58:07

WCF回調方法

2023-08-23 13:24:00

異步編程方法

2009-08-12 10:11:18

C# 回調函數

2011-05-20 17:19:25

回調函數

2023-04-28 15:20:37

JavaScript事件循環(huán)
點贊
收藏

51CTO技術棧公眾號