Promise

區別實例對象與函數對象html

  一、實例對象:new 函數產生的對象,稱爲實例對象,簡稱對象python

  二、函數對象:將函數做爲對象使用時,簡稱函數對象web

<script>
    function Fn(){//Fn函數
    }
    const fn = new Fn() //Fn是構造函數,fn是實例對象(簡稱對象)
    console.log(Fn.prototype)//Fn是函數對象
    Fn.bind({})//調用函數對象的bind方法
    $("#test") //jQuery函數
    $.get("/test") //jQuery函數對象,括號左邊是函數,點的左邊是對象
  </script>

兩種類型的回調函數ajax

  回調函數:回調函數就是一個參數,將這個函數做爲參數傳到另外一個函數裏面,當那個函數執行完以後,再執行傳進去的這個函數。這個過程就叫作回調編程

  同步回調數組

    理解:當即執行,徹底執行完了才結束,不會放入到回調隊列中promise

    例子:數組遍歷相關的回調函數,Promise的excutor函數異步

  異步回調async

    理解:不會當即執行,會放入到隊列中未來執行異步編程

    例子:定時器回調、ajax、Promise的成功|失敗的回調

<script>
    //一、同步回調函數
    const arr = [1,2,3]
    arr.forEach((item) =>{//遍歷回調函數,同步回調函數,不會放入隊列,一上來就要執行完
        console.log(item)
    })
    console.log("forEach函數以後")
    //二、異步回調函數
    setTimeout(() => {//異步回調函數,會放入隊列中未來執行
        console.log("timeout callback()")
    }, 0)
    console.log("setTimeout函數以後")//先於setTimeout的回調函數執行
</script>

JS中的error處理

  一、錯誤的類型

    一、Error:全部錯誤的父類型

    二、ReferenceError:引用的變量不存在

    三、TypeError:數據類型不正確的錯誤

    四、RangeError:數據值再也不其容許的範圍內

    五、SyntaxError:語法錯誤

  二、錯誤處理

    一、捕獲錯誤:try ... catch

    二、拋出錯誤:throw error

  三、錯誤對象

    message屬性:錯誤相關信息

    stack屬性:函數調用棧記錄信息

<script>
    //一、常見的內置錯誤
    //console.log(aaa) //ReferenceError: aaa is not defined
    console.log("----")//沒有捕獲error,下面的代碼不會執行
    let b = null
    //console.log(b.xx) //TypeError: b is null
    // function fn(){
    //     fn()
    // }
    // fn() //RangeError: Maximum call stack size exceeded
    const c = """" //SyntaxError: unexpected token: string literal

  //二、錯誤處理
    try{
        let d
        console.log(d.xxx)
    }catch(error){
        console.log(error.message)//d is undefined
        console.log(error.stack)// @file:///home/xdl/python/web/day01/code/01_html.html:71:3
    }
    console.log("出錯以後")//能夠正常執行
    //拋出異常
    function something(){
        if(Date.now()%2===1){
            console.log("當前時間爲奇數,能夠執行任務")
        }else{//若是時間爲偶數拋出異常,由調用者來處理
            throw new Error("當前時間爲偶數,沒法執行任務")
        }
    }
    try{
        something()
    }catch(error){
        console.log(error.message)//當前時間爲偶數,沒法執行任務
    }
</script>

promise的理解和使用

  一、promise是什麼?

    理解:

      一、抽象表達:promise是JS中進行異步編程的新的解決方案(以前是純回調的方式)

      二、具體表達:

        一、從語法上來講:promise是一個構造函數

        二、從功能上來講:promise對象用來封裝一個異步操做並能夠獲取其結果

    promise的狀態改變:

      一、pedding變爲resolved

      二、pedding變爲rejected

      說明:只有這兩種,且一個promise對象只能改變一次,不管變爲成功仍是失敗,都會有一個結果數據,成功的結果數據通常稱爲value,失敗的結果數據通常稱爲reason

    promise的基本使用

<script>
    //一、建立一個新的promise對象
    const p = new Promise((resolve, reject) => {//執行器函數,同步回調
        //二、執行異步任務
        setTimeout(() => {
            const time = Date.now() //若是當前時間是偶數表明成功,不然表明失敗
            if (time % 2 === 0){
                //3.一、若是成功,調用resolve(value)
                resolve("成功的數據,time=" + time)
            }else{
                //3.二、若是失敗,調用reject(reason)
                reject("失敗的數據,time=" + time)
            }  
        },1000)
    })
    p.then(
        (value) => {//接收穫得成功的value數據,onResolved
            console.log("成功的回調", value)
        },
        (reason) => {//接收穫得失敗的reason數據, onRejected
            console.log("失敗的回調", reason)
        }
    )
</script>   

  二、爲何要使用promise

     一、指定回調函數的方式更加靈活:

      舊的:必須在啓動異步任務前指定

      promise:啓動異步任務 => 返回promise對象=>給promise對象綁定回調函數(甚至能夠在異步執行完成以後)

    二、支持鏈式調用,能夠解決回調地獄問題

      什麼是地獄問題?回調函數嵌套調用,外部回調函數異步執行的結果是嵌套的回調函數執行的條件

      回調地獄的缺點?不便於閱讀,不便於異常處理

      解決方案?promise鏈式調用

      終極解決方案?async、await

  三、如何使用promise

    API

      一、Promise構造函數:Promise(excutor){}

        excutor函數:同步執行(resolve, reject)=> {}

        reslove函數:內部定義成功時咱們調用的函數value=>{}

        reject函數:內部定義失敗時咱們調用的函數 reason=>{}

        說明:excutor會在promise內部當即同步回調,異步操做在執行器中執行

      二、Promise.prototype.then方法:(onResolved, onRejected)=>{}

        onResolved函數:成功的回調函數 (value)=>{}

        onRejected函數:失敗的回調函數(reason)=>{}

        說明:指定用於獲得成功value的成功回調和用於獲得失敗reason的失敗回調,返回一個新的promise對象

      三、Promise.prototype.catch方法:(onRejected)=>{}

        onRejected函數:失敗的回調函數(reason)=>{}

        說明:then()的語法糖,至關於:then(undefined,onRejected)

new Promise((resolve, reject) =>{
        setTimeout(()=>{
            resolve("成功的數據")
            //reject("失敗的數據") // 只會執行第一個
        }, 1000)
    }).then(
        (value) => {
            console.log("onReaolved()1",value)
        }
    ).catch(
        (reason) => {
            console.log("onRejected()1", reason)
        }
    )

      四、Promise.resolve方法:(value)=> {}

        value:成功的數據或promise對象

        說明:返回一個成功或失敗的promise對象

      五、Promise.reject方法:(reason)=>{}

        reason:失敗緣由

        說明:返回一個失敗的promise對象

  /產生一個成功值爲1的promise對象
    const p1 = new Promise((resolve, reject)=>{
        resolve(1)
    })
    const p2 = Promise.resolve(2)
    const p3 = Promise.reject(3)
    p1.then(value=>{console.log(value)})
    p2.then(value=>{console.log(value)})
    p3.then( null, reason=>{console.log(reason)})
    p3.catch(reason=>{console.log(reason)})

      六、Promise.all方法:(promise)=>{}

        promise:包含n和promise的數組

        說明:返回一個新的promise,只有全部的promise都成功才成功,只要有一個失敗了就直接失敗

const p1 = new Promise((resolve, reject)=>{
        resolve(1)
    })
    const p2 = Promise.resolve(2)
    const p3 = Promise.reject(3)
    const pAll = Promise.all([p1,p2,p3])
    pAll.then(
        values => {
            console.log("all onResolved()", values)//若是成功將返回一個數組
        },
        reason =>{
            console.log("all onRejected()", reason)//3
        }
    )

      七、Promise.race方法:(promise)=>{}

        promise:包含n和promise的數組

        說明:返回一個新的promise,第一個完成的promise的結果狀態就是最終的結果狀態  

//產生一個成功值爲1的promise對象
    const p1 = new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(1)
        })
    })
    const p2 = Promise.resolve(2)
    const p3 = Promise.reject(3)
    const pRace = Promise.race([p1,p2,p3])
    pRace.then(
        value => {
            console.log("race onResolved()", value)
        },
        reason =>{
            console.log("race onRejected()", reason)
        }
    )

promise的關鍵問題

  一、如何改變Promise的狀態

    一、resolve(value):若是當前是pedding就會變爲resolved

    二、reject(reason):若是當前是pedding就會變爲rejected

    三、拋出異常:若是當前狀態是pedding就會變爲rejeceted

const p = new Promise((resolve, reject) =>{
        //resolve(1)//promies變爲resolved成功狀態
        //reject(2)//promise變爲rejected失敗狀態
        //throw new Error("出錯了")//拋出異常promise變爲rejected失敗狀態,reason 爲拋出的error
        throw 3
    });
    p.then(
        reason => {console.log("reason:", reason)}//3
    )

  二、一個promise指定多個成功或失敗回調函數,都會調用嗎?

    當promise改變爲對應狀態時都會調用

const p = new Promise((resolve, reject) =>{
        resolve(1)
        
    });
    p.then(
        value => {console.log("value1:", value)}//value1: 1
    )
    p.then(
        value => {console.log("value2:", value)}//value2: 1
    )

  三、改變promise狀態和指定回調函數誰先誰後?

    一、都有可能,正常狀況下時先指定回調函數再改變狀態,但也能夠先改變狀態再指定回調函數

    二、如何先改變狀態再指定回調?

      一、在執行器中直接調用resolve()/reject()

      二、延遲更長時間才調用then()

//如何先改變狀態,後指定回調函數
    new Promise((resolve, reject) =>{
        reject(1)//先改變的狀態(同時指定數據)    
    }).then(//後指定回調函數,異步執行回調函數
        value => {console.log("value:", value)},
        reason => {console.log("reason:", reason)}
    )

    三、何時才能獲得數據?

      一、若是先指定回調,那麼狀態發生改變時,回調函數就會調用,獲得數據

      二、若是先改變的狀態,那麼指定回調時,回調函數就會調用,獲得數據

new Promise((resolve, reject) =>{
        setTimeout(()=>{
            resolve(1)//後改變的狀態(同時指定數據),異步執行回調函數
        }, 1000)    
    }).then(//先指定回調函數,保存當前指定的回調函數
        value => {console.log("value1:", value)}//value1: 1
    )

  四、promise.then()返回的新的promise的結果狀態由什麼決定?

    一、簡單表達:由then()指定的回調函數執行的結果決定

    二、詳細表達:

      一、若是拋出異常,新promise變爲rejected,reason爲拋出的異常

      二、若是返回的是非promise的任意值,新的promise變爲resolved,value爲返回的值

      三、若是返回的是另外一個新promise,此promise的結果就會成爲新promise的結果 

new Promise((resolve, reject) =>{
        resolve(1)
        //reject(1)
    }).then(
        value => {
            console.log("onResolved1():", value)
            //return 2
            //return Promise.resolve(3)
            //return Promise.reject(4)
            throw 5
        },
        reason => {
            console.log("onRejected1():", reason)
        }
    ).then(
        value => {
            console.log("onResolved2():", value)
        },
        reason => {
            console.log("onRejected2():", reason)
        }
    )

  五、promise如何串連多個操做任務

    一、promise的then()返回一個新的promise,能夠當作then()的鏈式調用

    二、經過then的鏈式調用串連多個同步/異步任務

new Promise((resolve, reject) =>{
        setTimeout(()=>{
            console.log("執行任務1(異步)")
            resolve(1)
        },1000);
    }).then(
        value => {
            console.log("任務1的結果:", value)
            console.log("執行任務2(同步):")
            return 2
        }
    ).then(
        value => {
            console.log("任務2的結果():", value)
            return new Promise((resolve, reject)=>{
                setTimeout(()=>{
                    console.log("執行任務3(異步)")
                    resolve(3)
                },1000)
            })
        }
    ).then(
        value => {
            console.log("任務3的結果", value)
        }
    )

  六、promise異常傳透?

    一、當使用promise的then鏈式調用時,能夠在最後指定失敗的回調

    二、前面任何操做出了異常,都會傳到最後失敗的回調中處理

new Promise((resolve, reject) =>{
        resolve(1)
        //reject(1)
    }).then(
        value => {
            console.log("onResolveed1():", value)
            return Promise.reject(2)
        }
    ).then(
        value => {
            console.log("onResolveed2():", value)
            return 3
        }
    ).then(
        value => {
            console.log("onResolveed3()", value)
        }
    ).catch(reason => {
        console.log("onRejected1()", reason)
    })

  七、中斷promise鏈?

    一、當時用promise的then的鏈式調用時,在中間中斷,再也不調用後面的回調函數

    二、辦法:在回調函數中返回一個pedding狀態的promise對象

new Promise((resolve, reject) =>{
        resolve(1)
        //reject(1)
    }).then(
        value => {
            console.log("onResolveed1():", value)
            return Promise.reject(2)
        }
    ).then(
        value => {
            console.log("onResolveed2():", value)
            return 3
        }
    ).then(
        value => {
            console.log("onResolveed3()", value)
        }
    ).catch(reason => {
        console.log("onRejected1()", reason)
        return new Promise(()=>{})//返回一個pedding狀態的promise對象,中斷promise鏈
    }).then(
        value => {
            console.log("onResolved4", value)
        },
        reason => {
            console.log("onRejected2()", reason)
        }
    )

async與await

  async函數

    一、函數的返回值爲promise對象

    二、promise對象的結果由async函數執行的返回值決定

// async函數的返回值是一個promise對象
    //asyn函數返回的promise的結果由函數執行的結果決定
    async function fn1(){
        //return 1
        throw 2
    }
    const res = fn1()
    console.log(res)
    res.then(
        value =>{
            console.log("onResolved", value)
        },
        reason => {
            console.log("onRejected",reason)
        }
    )

  await表達式

    一、await右側的表達式通常爲promise對象,但也能夠是其餘的值 

     二、若是表達式是promise對象,await返回的是promise成功的值

    三、若是表達式是其餘值,直接將此值做爲await的返回值

function fn2(){
        return Promise.resolve(2)
    }
    async function fn3(){
        //const value = await fn2() // await右側表達式爲promise,獲得的結果就是promise成功的value
        const value = await 6 //await右側表達式不是Promis,獲得的結果就是它本省
        console.log("value:",value)
    }
    fn3()

  注意:

    await必須寫在async函數中,可是async函數中能夠沒有await

    若是await的promise失敗了,就會拋出異常,須要經過try...catch來捕獲處理

 JS異步之宏隊列與微隊列

  一、JS中用來存儲執行回調函數的隊列包含2個不一樣特定的隊列

  二、宏隊列:用來保存帶執行的宏任務,好比:定時器回調,DOM事件回調,ajax回調

  三、微隊列:用來保存待執行的微任務,好比:promise的回調,MutationObserver的回調

  四、JS執行時會區別這2兩個隊列

    一、JS引擎首先必須先執行全部的初始化同步任務代碼

    二、每次準備取出第一個宏任務前,都要講全部的微任務一個一個取出來執行

相關文章
相關標籤/搜索