欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中async與await實現(xiàn)原理與細(xì)節(jié)

 更新時間:2022年09月16日 14:43:32   作者:愛哭的趙一一???????  
這篇文章主要介紹了JavaScript中async與await實現(xiàn)原理與細(xì)節(jié),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

一、回調(diào)地獄

在es6興起之后許多人都開始使用promise,promise目的是解決es5中的回調(diào)地獄(callback hell),那么什么是回調(diào)地獄呢?先來提一個需求,現(xiàn)在需要發(fā)送n個request請求,第二個請求參數(shù)需要第一個請求的結(jié)果,第三個請求的參數(shù)需要第二個請求的結(jié)果,以此類推... ,在沒有promise的條件下,我們不難使用callback寫出如下的代碼:

function ajax(url, callback) {
    setTimeout(() => {
        callback(Math.random() + url)
    }, 1000);
}

function request() {
    ajax('url1', (res1 => {
        ajax(`url2?random=${res1}`, (res2) => {
            ajax(`url3?random=${res2}`, (res3) => {
                ajax(`url4?random=${res3}`, (res4) => {
                    // do something
                })
            })
        })
    }))
}
request()

二、Promise

這樣確實能實現(xiàn)我們的需求,但是這樣子的代碼有什么缺點呢?不難看出我們的request函數(shù)越來越像個三角形 ,代碼集中在上部分,下半部分全都是我們的括號,代碼閱讀性極差! 這時候我們的promise應(yīng)運而生了,使用promise我們可以這樣重構(gòu)我們的代碼如下:

function ajax(url) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(Math.random() + url)
        }, 1000);
    })
}

function request() {
    ajax('url1').then(res1 => {
        ajax(`url2?random=${res1}`).then((res2) => {
            ajax(`url3?random=${res2}`).then((res3) => {
                ajax(`url4?random=${res3}`).then((res4) => {
                    // do something
                })
            })
        })
    })
}
request()

肯定有人說,這不還是像個三角形嗎?這樣使用promise有什么意義呢?此時我們可以借助promise的鏈?zhǔn)秸{(diào)用重構(gòu)成下面這樣:

function ajax(url) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(Math.random() + url)
        }, 1000);
    })
}

function request() {
    ajax('url1').then(res1 => {
        return ajax(`url2?random=${res1}`)
    }).then(res2 => {
        return ajax(`url3?random=${res2}`)
    }).then(res3 => {
        return ajax(`url4?random=${res3}`)
    }).then(res4 => {
        // do something
    })
}

request()

相對于之前的回調(diào)地獄,此時我們的代碼是不是比較清晰了。但是!這還不夠!這看上去還不夠直觀。我們想要的是閱讀異步代碼,類似于閱讀同步代碼的方式一樣方便。

三、生成器(generator)

生成器是es6新增的語法,它是一個特殊的迭代器,它可以用來暫停我們函數(shù)的執(zhí)行!這個功能非常強大! 生成器的語法是,在聲明函數(shù)時在后面增加一個 * 號,那么這個函數(shù)就是生成器函數(shù),直接調(diào)用該函數(shù)得到的是一個生成器句柄,該生成器是不會執(zhí)行的,必須要調(diào)用生成器句柄的next()方法后,生成器才會執(zhí)行,并且執(zhí)行到我們的yield處(如果存在yield就執(zhí)行到第一個yield,不存在則直接執(zhí)行完畢),該方法的返回值一個對象,結(jié)構(gòu)是 {done: true/false, value: 我們yield后面跟的值} ,如果執(zhí)行到該生成器函數(shù)末尾則 done為true。 關(guān)于生成器的知識可以點此JavaScript中的迭代器和可迭代對象與生成器

function* foo() {
    console.log('======');
    const a = yield 1;
    console.log('a',a);
}

const g = foo()
console.log('11111111')
const res1 = g.next()
console.log(res1)
const res2 = g.next('22222')
console.log(res2)

上面代碼打印順序為:

11111111
======
{done: false, value: 1}
'a','22222'
{done: true, value: undefined}

細(xì)心的你一定看出了,我們在next方法中傳的參數(shù)會賦值給生成器函數(shù)中的yield 左側(cè),并可以在生成器中拿到這個值后進行使用。

四、使用生成器同步化promise

掌握了生成器的知識我們就可以使用生成器來將我們的promise鏈?zhǔn)秸{(diào)用進行重構(gòu)如下:

function ajax(url) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(Math.random() + url)
        }, 1000);
    })
}

function* request() {
    const res1 = yield ajax('url1')
    const res2 = yield ajax(`url2?random=${res1}`)
    const res3 = yield ajax(`url3?random=${res2}`)
    const res4 = yield ajax(`url4?random=${res3}`)
    //    do something
    console.log(res4);
}
// 開始調(diào)用我們的生成器
const generator = request();
generator.next().value.then(res1 => {
    generator.next(res1).value.then(res2 => {
        generator.next(res2).value.then(res3 => {
            generator.next(res3).value.then(res4 => {
                generator.next(res4)
            })
        })
    })
})

可以看到我們的生成器還是三角形,優(yōu)化一下成鏈?zhǔn)秸{(diào)用如下:

generator.next().value.then(res1 => {
    return generator.next(res1).value
}).then(res2 => {
    return generator.next(res2).value
}).then(res3 => {
    return generator.next(res3).value
}).then(res4 => {
    generator.next(res4)
})

此時,我們的主函數(shù)已經(jīng)非常像同步代碼了,但是缺點是我們目前必須手動調(diào)用該生成器,并且request主函數(shù)里面我們不知道有多少次yield調(diào)用,因此我們的生成器也不能手動調(diào)用多次,這時,我們將該生成器調(diào)用代碼進行重構(gòu),重構(gòu)成可以自動執(zhí)行我們的生成器的函數(shù),不需要關(guān)心request內(nèi)部有多少次yield使用,重構(gòu)如下:

function ajax(url) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(Math.random() + url)
        }, 1000);
    })
}
function* request() {
    const res1 = yield ajax('url1')
    const res2 = yield ajax(`url2?random=${res1}`)
    const res3 = yield ajax(`url3?random=${res2}`)
    const res4 = yield ajax(`url4?random=${res3}`)
    //    do something
    console.log(res4);
}
function execGenerator(generatorFn) {
    const generator = generatorFn();
    function exec(res) {
        const { done, value } = generator.next(res)
        if (!done) {
            value.then(exec)
        }
    }
    exec()
}
execGenerator(request)

我們增加了一個自動執(zhí)行函數(shù)execGenerator,該函數(shù)接受一個生成器參數(shù),并且在內(nèi)部自動進行遞歸調(diào)用,直至返回值的 done 屬性為 true,此時我們的使用方式只需要定義一個request生成器函數(shù),并且執(zhí)行一下我們的自動執(zhí)行函數(shù) execGenerator ,我們的request就能像同步代碼一樣盤跑起來了,并且看起來非常直觀。

五、async、await異步代碼究極解決方案

其實async與await是我們上面生成器的語法糖而已,在內(nèi)部做的事情跟我們使用生成器做的事情是一樣的,使用方式如下:

function ajax(url) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve(Math.random() + url)
        }, 1000);
    })
}

async function request() {
    const res1 = await ajax('url1')
    const res2 = await ajax(`url2?random=${res1}`)
    const res3 = await ajax(`url3?random=${res2}`)
    const res4 = await ajax(`url4?random=${res3}`)
    //    do something
    console.log(res4);
}

看起來是不是跟我們的生成器request函數(shù)非常類似呢?使用asyncawait可以讓我們省去寫execGenerator函數(shù)的步驟,更加方便了我們的開發(fā)!

到此這篇關(guān)于JavaScript中async與await實現(xiàn)原理與細(xì)節(jié)的文章就介紹到這了,更多相關(guān)JS 中async與await 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解js正則表達式驗證時間格式xxxx-xx-xx形式

    詳解js正則表達式驗證時間格式xxxx-xx-xx形式

    本篇文章主要介紹了詳解js正則表達式驗證時間格式xxxx-xx-xx形式,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • JavaScript中判斷整數(shù)的多種方法總結(jié)

    JavaScript中判斷整數(shù)的多種方法總結(jié)

    這篇文章主要介紹了JavaScript中判斷整數(shù)的多種方法總結(jié),本文總結(jié)了5種判斷整數(shù)的方法,如取余運算符判斷、Math.round、Math.ceil、Math.floor判斷等,需要的朋友可以參考下
    2014-11-11
  • javascript實現(xiàn)電商放大鏡效果

    javascript實現(xiàn)電商放大鏡效果

    這篇文章主要為大家詳細(xì)介紹了javascript實現(xiàn)電商放大鏡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • element-ui的表單驗證清除校驗提示語的解決方案

    element-ui的表單驗證清除校驗提示語的解決方案

    對表單域中的數(shù)據(jù)進行校驗的時候,其中有一項比較特殊,不是簡單的輸入框,下拉框這些表單元素,而是自己寫的一個el-table的選擇彈窗,本文給大家介紹element-ui的表單驗證如何清除校驗提示語,感興趣的朋友一起看看吧
    2024-01-01
  • 微信小程序時間選擇插件使用詳解

    微信小程序時間選擇插件使用詳解

    這篇文章主要為大家詳細(xì)介紹了微信小程序時間選擇插件的使用方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-12-12
  • javascript 按鍵事件(兼容各瀏覽器)

    javascript 按鍵事件(兼容各瀏覽器)

    本篇文章主要是對javascript中的按鍵事件進行了詳細(xì)的總結(jié)介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2013-12-12
  • javascript實現(xiàn)簡易計算器的代碼

    javascript實現(xiàn)簡易計算器的代碼

    下面小編就為大家?guī)硪黄猨avascript實現(xiàn)簡易計算器的代碼小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-05-05
  • JavaScript中的事件委托及好處

    JavaScript中的事件委托及好處

    事件就是onclick,onmouseover,onmouseout,等就是事件,委托呢,就是讓別人來做,這個事件本來是加在某些元素上的,然而你卻加到別人身上來做,完成這個事件,本文給大家重點介紹js中的事件委托及好處,一起看看吧
    2016-07-07
  • js實現(xiàn)多圖左右切換功能

    js實現(xiàn)多圖左右切換功能

    這篇文章主要介紹了js實現(xiàn)多圖左右切換功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-08-08
  • JS獲取下拉列表所選中的TEXT和Value的實現(xiàn)代碼

    JS獲取下拉列表所選中的TEXT和Value的實現(xiàn)代碼

    本篇文章主要是對JS獲取下拉列表所選中的TEXT和Value的實現(xiàn)代碼進行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助
    2014-01-01

最新評論