JS異步編程,回調函數與promise


  Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大。它由社區最早提出和實現,ES6 將其寫進了語言標准,統一了用法,原生提供了Promise對象。

  ES6之前,JavaScript中異步編程分為3類:DOM事件(如onclick)、網絡請求(如ajax)、定時器(setTimeout/setInterval)。他們均使用回調函數來進行異步調用。當回調函數中嵌套了回調函數,甚至是多層回調時,編碼就不夠直觀了。而使用Promise就能通過同步的編碼方式實現異步調用。

1.多層回調:使用setTimeout()函數執行3層嵌套的異步回調,編碼不直觀

 1   function async(){
 2     setTimeout(function(){  //回調函數1
 3       console.log(1);  
 4       setTimeout(function(){  //回調函數2
 5         console.log(2);
 6         setTimeout(function(){  //回調函數2
 7           console.log(3);
 8         },1000);
 9       },1000);
10     },1000)
11   }
12 
13   async();
14 
15   //調用結果:1s后打印1 2s后打印2 3s后打印3

 

2.promise:以同步順序編碼來執行3次異步回調

通過return new Promise(),如果該promise中含有異步調用(setTimeout),則會等到異步調用中執行resolve()時才會執行后面的then函數。

 1   new Promise(function(resolve,reject){
 2     //立即執行
 3     console.log('new promise');
 4     setTimeout(() => {  //回調函數1
 5       console.log(11);  //11
 6       resolve(12);  //返回value給下一個then函數
 7     }, 1000);
 8   }).then(function(value){  //回調函數2
 9       //上一個promise resolve()后執行
10       console.log(value);  //12
11       return new Promise(function(resolve,reject){
12         setTimeout(() => {
13           console.log(21);  //21
14           resolve(22);
15         }, 1000);  
16       });
17     }).then(function(value){  //回調函數3
18       //上一個promise resolve()后執行
19       console.log(value);  //22
20       setTimeout(() => {
21         console.log(31);   //31
22       }, 1000);  
23     });
24 
25   //執行結果:立即打印new promise,1s后打印11/12,2s后打印21/22,3s后打印31

 

3.如果then的回調函數中沒有聲明式的return new Promise(); 那么return會自動返回一個新的promise,所以也可以鏈式執行then函數。

return自動返回的promise中並沒有異步操作(setTimeout沒有在promise中),所以后面的then函數是立即執行的。

可以參考MDN中關於then返回值的說明:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/then

 1   new Promise(function(resolve,reject){
 2     //立即執行
 3     console.log('new promise');
 4     setTimeout(() => {  //回調函數1
 5       console.log(11);  //11
 6       resolve(12);  //返回value給下一個then函數
 7     }, 1000);
 8   }).then(function(value){  //回調函數2
 9       //上一個promise resolve()后執行
10       console.log(value);  //12
11       setTimeout(() => {
12           console.log(21);  //21
13         }, 1000);  
14       return 22;
15     }).then(function(value){  //回調函數3
16       //上一個promise resolve()后執行
17       console.log(value);  //22
18       setTimeout(() => {
19         console.log(31);   //31
20       }, 1000);  
21     });
22 
23 //執行結果:立即打印new promise,1s后打印11/12/22,2s后打印21/31

 

4.異步編程原理:

  JS是單線程指的是它的執行棧是單線程的(即JavaScript引擎的線程),稱為主線程。JS 會創建一個類似於 while (true) 的循環,每執行一次循環體的過程稱之為 Tick。每次 Tick 的過程就是查看任務隊列中是否有待處理任務(DOM事件/網絡請求/定時器的回調函數),如果有則取出相關回調函數放入執行棧中由主線程執行。

  異步操作會將相關回調添加到任務隊列中。而不同的異步操作添加到任務隊列的時機也不同,onclick 由瀏覽器內核的 DOM Binding 模塊來處理,當事件觸發的時候,回調函數會立即添加到任務隊列中。setTimeout 會由瀏覽器內核的 timer 模塊來進行延時處理,當時間到達的時候,才會將回調函數添加到任務隊列中。ajax 則會由瀏覽器內核的 network 模塊來處理,在網絡請求完成返回之后,才將回調添加到任務隊列中。

  瀏覽器內核實現允許多個線程異步執行JavaScript引擎的線程外,還存在事件觸發進程、計時器觸發進程、http請求線程等,他們與JavaScript引擎的線程是互不影響的,不會造成阻塞。即JavaScript引擎的線程阻塞后,事件仍然會被觸發,但只是事件的回調函數無法添加到任務隊列,或者無法從任務隊列添加到執行棧中。

異步原理參考鏈接:https://blog.csdn.net/qdq2014/article/details/72383725/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM