最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

一、回調(diào)地獄

在es6興起之后許多人都開始使用promise,promise目的是解決es5中的回調(diào)地獄(callback hell),那么什么是回調(diào)地獄呢?先來提一個(gè)需求,現(xiàn)在需要發(fā)送n個(gè)request請求,第二個(gè)請求參數(shù)需要第一個(gè)請求的結(jié)果,第三個(gè)請求的參數(shù)需要第二個(gè)請求的結(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

這樣確實(shí)能實(shí)現(xiàn)我們的需求,但是這樣子的代碼有什么缺點(diǎn)呢?不難看出我們的request函數(shù)越來越像個(gè)三角形 ,代碼集中在上部分,下半部分全都是我們的括號,代碼閱讀性極差! 這時(shí)候我們的promise應(yīng)運(yùn)而生了,使用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()

肯定有人說,這不還是像個(gè)三角形嗎?這樣使用promise有什么意義呢?此時(shí)我們可以借助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)地獄,此時(shí)我們的代碼是不是比較清晰了。但是!這還不夠!這看上去還不夠直觀。我們想要的是閱讀異步代碼,類似于閱讀同步代碼的方式一樣方便。

三、生成器(generator)

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

上面代碼打印順序?yàn)椋?/strong>

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

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

四、使用生成器同步化promise

掌握了生成器的知識我們就可以使用生成器來將我們的promise鏈?zhǔn)秸{(diào)用進(jìn)行重構(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í),我們的主函數(shù)已經(jīng)非常像同步代碼了,但是缺點(diǎn)是我們目前必須手動調(diào)用該生成器,并且request主函數(shù)里面我們不知道有多少次yield調(diào)用,因此我們的生成器也不能手動調(diào)用多次,這時(shí),我們將該生成器調(diào)用代碼進(jìn)行重構(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)

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

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

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

相關(guān)文章

最新評論

乐业县| 彭阳县| 万年县| 新乡市| 昭通市| 宾川县| 凉城县| 黄石市| 溆浦县| 高州市| 安多县| 马关县| 平罗县| 东乌珠穆沁旗| 漳州市| 舞钢市| 洪湖市| 宣城市| 彭山县| 县级市| 金溪县| 涡阳县| 河南省| 林西县| 遵义市| 岑溪市| 渑池县| 淄博市| 邳州市| 镇康县| 镇江市| 南充市| 土默特右旗| 抚顺市| 柳州市| 英山县| 利辛县| 海丰县| 滁州市| 紫阳县| 建始县|