pormise
假設現在我剛認識你,需要和你說話,但是我普通話不夠標準,需要間隔一秒鐘才能說一句話,以此讓你可以慢慢思考。這樣的話我們就需要用到定時器。
最沙雕的程式碼如下:
setTimeout( function(){ console.log('你好,我是saoge'); setTimeout( function(){ console.log('很高興認識你'); setTimeout( function(){ console.log('交個朋友吧'); },1000) },1000) },1000)
但是這種程式碼,是根本沒有可讀性的。因此我們還有另一種寫法。
function helloOne(next){ setTimeout(function(){ console.log('你好,我是saoge'); next(); },1000) } function helloTow(next){ setTimeout(function(){ console.log('你好,很高興認識你'); next(); },1000) } function helloThree(){ setTimeout(function(){ console.log('交個朋友吧'); },1000) } helloOne(function(){ helloTow(function(){ helloThree() }) })
用回撥函式來實現程式碼看上去會有邏輯性的多,但是在呼叫的時候也會存在層層巢狀的問題,如果這個時候我是個話癆,要和你說很多據話,那麼用回撥函式寫出來的程式碼也是相當恐怖的,而且採用這種方式並不能很方便的改變執行的順序等。總而言之就是因為總總不好,所以出現了更好的方式promise。
使用Promise
使用new來建立一個Promise的例項。
var promise = new Promise(function(resolve,reject){ setTimeout(function(){ resolve('你好,我是saoge'); reject(new Error('發生錯誤')); // if(false){ // resolve('你好,我是saoge'); // }else{ // reject(new Error('發生錯誤')) // } },1000) }) promise.then(function(data){ console.log(data); },function(err){ console.log(err) }) //使用catch promise.then(function(data){ console.log(data); }).catch(function(err){ console.log(err); })
我們來一步一步的分析上述案例。
在上述例項中,Promise傳入了兩個形參 resolve 和 reject 這兩個引數的回撥,代表成功和失敗,如果執行正常,就呼叫resolve,否則就呼叫reject。上程式碼:
var promise = new Promise(function(resolve,reject){ //成功時呼叫resolve //失敗時呼叫reject })
同時,promise例項具有then方法,then方法接受兩個引數,第一個引數時resolve執行成功的回撥,第二個引數reject 是執行失敗的回撥。
因此,在上述案例中,最終會輸出 "你好我是騷哥"
我們可以用if語句來模擬一下執行失敗的情況,這個時候輸出的就是 Error:發生錯誤
同時,Promise例項還提供了一個catch()方法,該方法和then()方法接收的第二個引數一樣,用來執行reject的回撥。
var promise = new Promise(function(resolve,reject){ //成功時呼叫resolve //失敗時呼叫reject }) promise.then( resolve的回撥 , reject 的回撥(可選) ); promise.catch(reject的回撥);
我們用Promise來實現一下最初對話的案例。
function helloOne() { return new Promise( function(next) { setTimeout(function() { console.log('你好,我是saoge'); next(); }, 1000) }) } function helloTwo() { return new Promise( function(next) { setTimeout(function() { console.log('你好,很高興認識你'); next(); }, 1000) }) } function helloThree() { return new Promise( function(next) { setTimeout(function() { console.log('交個朋友吧'); next(); }, 1000) }) } helloOne().then(helloTwo).then(helloThree);
和使用回撥的區別在於,我們將要執行的程式碼放在了Promise例項中,這樣,在我們最後需要執行的時候,只需要用then()方法去呼叫即可,語法結構簡單,即使我想說再多的話也不會造成程式碼結構混亂。且在這裡使用了Promise方法之後,如果是我想要改變程式碼執行順序的話只需要改變then()方法傳入的值即可。
非同步之間傳參
function hello(){ var text='你好,我是saoge'; setTimeout(function(){ console.log(text); say(text); },1000) } function say(text){ setTimeout(function(){ console.log(text) },1000) } hello();
Promise在執行成功的時候,會呼叫resolve,因此,我們就可以用resolve來傳值。
var pro = new Promise((resolve, reject) => { setTimeout(function() { var text = '你好,我是saoge'; console.log(text); resolve(text); }, 1000) }) pro.then(function(data) { setTimeout(function() { console.log(data); }, 1000) })
需要等待多個函式執行完畢再執行時:Promise.all()
function helloOne() { return new Promise( function(next) { setTimeout(function() { console.log('你好,我是saoge'); next(); }, 1000) }) } function helloTwo() { return new Promise( function(next) { setTimeout(function() { console.log('你好,很高興認識你'); next(); }, 2000) }) } function helloThree() { return new Promise( function(next) { setTimeout(function() { console.log('交個朋友吧'); next(); }, 3000) }) } Promise.all([helloOne(),helloTwo(),helloThree()]).then(function(){ setTimeout(function(){ console.log('可以嗎?') },1000) });
上面這段程式碼就會先在一秒鐘我說出你好,我是騷哥。然後再過一秒鐘我說你好,很高興認識你。再過一秒鐘說出交個朋友吧,我們可以看到在then()方法裡面有一個函式,是一秒鐘之後詢問你可以嗎?而這句話執行的時間是第四秒。也就是Promise.all中的函式執行完成之後再去執行hten()方法中的語句。
Promise.race()
function helloOne() { return new Promise( function(next) { setTimeout(function() { console.log('你好,我是saoge'); next(); }, 1000) }) } function helloTwo() { return new Promise( function(next) { setTimeout(function() { console.log('你好,很高興認識你'); next(); }, 2000) }) } function helloThree() { return new Promise( function(next) { setTimeout(function() { console.log('交個朋友吧'); next(); }, 3000) }) } Promise.race([helloOne(),helloTwo(),helloThree()]).then(function(){ setTimeout(function(){ console.log('可以嗎?') },1000) });
看上面這個例子,執行一秒之後輸出“你好,我是騷哥”,然後再過一秒鐘會輸出兩句話,“你好,很高興認識你”,“可以嗎?”,最後再輸出“交個朋友吧” 可以看出,在helloOne執行完畢之後,then()中的程式碼就開始執行了,和Promise.all()的不同就在於,只要有一個執行成功就去執行hten()中的程式碼。
async
1.async幹了什麼
async function helloOne(){ setTimeout(function(){ return("你好,我是騷哥"); },1000) } console.log(helloOne()) //Promise {<fulfilled>: undefined}
async 返回的是一個Promise物件。
async function helloOne(){ setTimeout(function(){ return("你好,我是騷哥"); },1000) } console.log(helloOne()); //Promise {<fulfilled>: undefined} helloOne().then(function(data){ console.log(data) //undefined })
我們嘗試用then()去獲取async函式中的值,但是返回的是undefined,且兩個輸出語句是同時執行的,所以說then()中的函式還沒有等到非同步函式執行完便執行了,因此這裡和Promise不太一樣。
function helloOne() { return new Promise((resolve,reject)=>{ setTimeout( function(){ resolve( '你好,我是saoge'); }, 1000) }); } function helloTwo(){ setTimeout( function(){ return '拜拜'; }, 1000) } async function say(){ var one = await helloOne() console.log(one) //你好,我是saoge var two = await helloTwo() console.log(two) //undefined } say()
直接看程式碼,可以發現,如果await 後面跟的是一個Promise物件,那麼將會等到Promise物件resolve,然後將resolve的值作為表示式的結果。如果不是以惡搞promise物件,那麼await的運算結果就是此時傳入的東西,兵不會有其他作用。