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

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

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

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

 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函數是當即執行的。async

能夠參考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/

相關文章
相關標籤/搜索