pormise和async

清塵莫風發表於2020-09-25

pormise

1.非同步問題

假設現在我剛認識你,需要和你說話,但是我普通話不夠標準,需要間隔一秒鐘才能說一句話,以此讓你可以慢慢思考。這樣的話我們就需要用到定時器。

最沙雕的程式碼如下:

            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的運算結果就是此時傳入的東西,兵不會有其他作用。

 

相關文章