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/
