亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JavaScript Generator函數(shù)使用分析

 更新時間:2022年10月18日 12:04:42   作者:月光曬了很涼快  
生成器Generator是JavaScript ES6引入的特性,它讓我們可以分段執(zhí)行一個函數(shù)。但是在談論生成器(Generator)之前,我們要先了解迭代器Iterator

1. Generator的定義和執(zhí)行

如果說 Promise 是為了解決回調(diào)地獄的難題出現(xiàn)的,那么 Generator 就是為了解決異步問題而出現(xiàn)的。

普通函數(shù),如果調(diào)用它會立即執(zhí)行完畢;Generator 函數(shù),它可以暫停,不一定馬上把函數(shù)體中的所有代碼執(zhí)行完畢,正是因為有這樣的特性,它可以用來解決異步問題。

定義一個 Generator 函數(shù),定義的方式和定義一個普通函數(shù)是類似的,不同之處在于它在 function 和函數(shù)名之間有一個*號。

Generator 函數(shù)返回是一個迭代器對象,需要通過 xx.next 方法來完成代碼執(zhí)行。在調(diào)用 generator 函數(shù)時,它只是進行實例化工作,它沒有讓函數(shù)體里面的代碼執(zhí)行,需要通過 next 方法來讓它執(zhí)行,比如像下面這樣:

function* gen() {
    console.log(1)
}
// 定義迭代器對象
const iterator = gen()
iterator.next() // 如果不執(zhí)行這一局代碼,1不會被打印

當 next 方法執(zhí)行時遇到了 yield 就會停止,直到你再次調(diào)用 next 方法。比如像下面這樣:

function* gen() {
    yield 1
    console.log('A')
    yield 2
    console.log('B')
    yield 3
    console.log('C')
    return 4
}
// 定義迭代器對象
const iterator = gen()
iterator.next() // 執(zhí)行 gen 函數(shù),打印為空,遇到 yield 1 停止執(zhí)行
iterator.next() // 繼續(xù)執(zhí)行函數(shù),打印 A,遇到 yield 2 停止執(zhí)行
iterator.next() // 繼續(xù)執(zhí)行函數(shù),打印 B,遇到 yield 3 停止執(zhí)行
iterator.next() // 繼續(xù)執(zhí)行函數(shù),打印 C

next 方法調(diào)用時,它是有返回值的,它的返回值就是 yield 后面的值或函數(shù)的返回值。比如下面這個例子:

// 同步代碼
function* gen() {
    yield 1
    console.log('A')
    yield 2
    console.log('B')
    yield 3
    console.log('C')
    return 4
}
// 定義迭代器對象
const iterator = gen()
// 異步代碼
console.log(iterator.next()) // 打印為空  next返回 {value:1,done:false}
console.log(iterator.next()) // A  next返回 {value:2,done:false}
console.log(iterator.next()) // B  next返回 {value:3,done:false}
console.log(iterator.next()) // C  next返回 {value:4,done:true},如果函數(shù)有return值,最后一個next方法,它的value值為return的值 value:4;如果沒有。值為 undefined

拓展:其實之所以我們說 Generator 能夠把異步變同步,是因為 Generator 函數(shù)中我們只需要寫同步代碼就可以,真正執(zhí)行異步操作的是迭代器對象。在復雜的業(yè)務邏輯中,大量使用迭代器對象來執(zhí)行異步操作,會使得代碼變得很不優(yōu)雅,于是 ES7 中就推出了 async await 方案來實現(xiàn)異步變同步。在 async await 方案中可以只書寫同步代碼,真正的異步操作被封裝在底層,這樣的寫法,使得代碼變優(yōu)雅了很多。

2. Generator中yield在賦值號左邊的情況

yield 在等號右邊時,它的返回值并不會返回給等號左邊的變量,依然會返回給 next 方法。

function* gen(num) {
    let r1 = yield 1
    console.log('r1', r1);
    let r2 = yield 2
    console.log('r2', r2);
    let r3 = yield 3
    console.log('r3', r3);
}
const iterator = gen()
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next())
console.log(iterator.next()) 

這是因為 generator 函數(shù)在遇到 yield 時就已經(jīng)暫停執(zhí)行了,并不會執(zhí)行到賦值操作,直到在執(zhí)行完 next 方法之后,才會繼續(xù)向下執(zhí)行賦值操作。如果我們想要 r1/r2/r3 有值,我們可以用 next 方法進行傳值。就像下面這樣:

function* gen(num) {
    let r1 = yield 1
    console.log('r1', r1);
    let r2 = yield 2
    console.log('r2', r2);
    let r3 = yield 3
    console.log('r3', r3);
}
const iterator = gen()
iterator.next() // 第一個 next 方法不用給值,即使給值也不會生效
iterator.next('A')
iterator.next("B")
iterator.next('C')

3. Generator函數(shù)嵌套使用

function* gen1() {
    yield 1
    yield 2
}
function* gen2() {
    yield 3
    // generator函數(shù)的嵌套
    // 這種寫法對應 方案1
    // yield gen1()
    yield* gen1()
    yield 4
}
const iterator = gen2()
console.log(iterator.next()); // {value:3,done:false}
// 如果我們想執(zhí)行到 gen1 中的 yield 值
// console.log(iterator.next()); // {value:generator實例,done:false}
// let itor = iterator.next().value
// console.log(itor.next()); // {value:1,done:false}
// console.log(itor.next()); // {value:2,done:false}
// 方案2
console.log(iterator.next()); // {value:1,done:false}  你需要在yield后面加一個*,讓它知道后面是一個generator對象
console.log(iterator.next()); // {value:2,done:false}
console.log(iterator.next()); // {value:4,done:false}
console.log(iterator.next()); // {value:undefined,done:true}

4. 使用generator函數(shù)完成網(wǎng)絡請求

// 使用generator來完成異步網(wǎng)絡請求,它還是要利用到promise
// 模擬網(wǎng)絡請求
function request(num = 1) {
    return new Promise((resolve, reject) => {
        return setTimeout(() => {
            resolve(++num)
        }, 1000);
    })
}
// generator函數(shù)中的代碼,發(fā)起的網(wǎng)絡請求它就類似于同步寫法
function* gen(num) {
    // yield右側(cè)是一個promise對象
    let r1 = yield request(10)
    console.log('r1', r1);
    let r2 = yield request(r1)
    console.log('r2', r2);
    let r3 = yield request(r2)
    console.log('r3', r3);
}
const iterator = gen(10)
iterator.next().value.then(ret1 => {
    iterator.next(ret1).value.then(ret2 => {
        iterator.next(ret2).value.then(ret3 => {
            iterator.next(ret3)
        })
    })
})

上面的寫法不夠優(yōu)雅,當有多個網(wǎng)絡請求時,異步操作部分的代碼會變得非常復雜,所以我們可以通過 co 庫中的迭代函數(shù)來改寫一下:

// 使用generator來完成異步網(wǎng)絡請求,它還是要利用到promise
// 模擬網(wǎng)絡請求
function request(num) {
    return new Promise((resolve, reject) => {
        return setTimeout(() => {
            resolve(++num)
        }, 1000);
    })
}
// generator函數(shù)中的代碼,發(fā)起的網(wǎng)絡請求它就類似于同步寫法
function* gen(num) {
    // yield右側(cè)是一個promise對象
    let r1 = yield request(10)
    console.log('r1', r1);
    let r2 = yield request(r1)
    console.log('r2', r2);
    let r3 = yield request(r2)
    console.log('r3', r3);
    let r4 = yield request(r3)
    console.log('r4', r4);
    let r5 = yield 'ok'
    console.log('r5', r5);
}
// 通過co庫實現(xiàn)
function co(generator, ...params) {
    const iterator = gen(...params)
    // 迭代函數(shù)
    const next = n => {
        let { value, done } = iterator.next(n)
        // 判斷一下value它是一個promise對象,如果不是promise對象則需要手動轉(zhuǎn)為promise對象,或拋異常
        if (value != undefined && typeof value.then != "function") {
            throw new Error('必須為promise對象')
            // value = Promise.resolve(value)
        }
        if (done) return;
        // value.then(ret => next(ret))
        value.then(next)
    }
    next(0)
}
co(gen, 100)

到此這篇關(guān)于JavaScript Generator函數(shù)使用分析的文章就介紹到這了,更多相關(guān)JS Generator內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論