地獄の解決方法

18679 ワード

地獄は何ですか?
    非同期のJavaScriptプログラム、またはコールバック関数を使ったJavaScriptプログラムは、直感的にスムーズに読まれにくく、大量のコードは以下のように終わります.簡単に言えば、関数がパラメータ層としてネストされているということです.コードはこのような形で展示されている時、私達が読むのに不便です.
setTimeout(function (name) {
    var catList = name + ','
    setTimeout(function (name) {
        catList += name + ','
        setTimeout(function (name) {
            catList += name
            console.log(catList)
        }, 200, 'Lion')
    }, 200, 'Jaguar')
}, 200, 'Panther')

// Panther,Janguar,Lion

解決コール地獄
1.分解function:各ステップを単一のfunctionに分解する
function buildCatList(list, returnVal, fn) {
    setTimeout(function (name) {
        var catList = list === '' ? name : list + ',' + name
        fn(catList)
    }, 200, returnVal)
}

buildCatList('', 'Panther', getJanguar)

function getJanguar(list) {
    buildCatList(list, 'Janguar', getLynx)
}

function getLynx(list) {
     buildCatList(list, 'Lion', print)
}

function print(list) {
    console.log(list)
}

// Panther,Janguar,Lion

   タイマーにおけるコールバック関数は、外層関数の作用領域にあり、パラメータを通して入ってきたので、大域変数が発生せず、コードを重複していません.しかし、Functionの分割方法は、単にコードブロックを分割するだけで、後続のメンテナンスに不利になることがあります.
2.Promiseチェーンで呼び出す方式
function buildCatList(list, returnVal) {
    return new Promise(function (resolve, reject) {
        setTimeout(function (name) {
            var catList = list === '' ? name : list + ',' + name
            resolve(catList)
        }, 200, returnVal)
    })
}

buildCatList('', 'Panther').then(function (res) {
	return buildCatList(res, 'Janguar')
}).then(function (res) {
	return buildCatList(res, 'Lion')
}).then(function (res) {
	console.log(res)
})

// Panther,Janguar,Lion

前の地獄の書き方を変えましたが、基本的には関数がセットされていて、見た目はそんなに綺麗ではありません.
3.Generator関数により実行を一時停止する効果方式
function getPanther(list) {
	return list + 'Panther' + ','
}

function getJaguar(list) {
    return list + 'Jaguar' + ','
}

function getLion(list) {
    return list + 'Lion'
}

function* buildCatList() {
    yield getPanther
    yield getJaguar
    yield getLion
}

//    
function run(fn){
    const gen = fn()      //    Generator   ,          (Iterator)
    var a = gen.next().value('')   //          next()   ,         value   done        
    var b = gen.next().value(a)
    var c = gen.next().value(b)
    console.log(c)
}

run(buildCatList)   //     

// Panther,Jaguar,Lion

    はゲナートを通じてより良い文法構造を提供できますが、ゲナートとyieldの文脈はここでは多少適切ではありません.
4.ES 8を通過する非同期関数async/await
  • asyncはこれはasync関数です.awaitはこの関数の中でしか使えません.
  • awaitはここでPromiseの戻りを待ってから、
  • を実行し続けると表しています.
  • awaitに続いているのはPromiseオブジェクトです.もちろん、他の戻り値は大丈夫です.すぐ実行します.
  • awaitが待っているのはPromiseオブジェクトですが、書く必要はありません.then()は、戻り値
  • を直接に得ることができます.
    function buildCatList(list, returnVal) {
    	return new Promise(function (resolve, reject) {
        	setTimeout(function (name) {
            	var catList = list === '' ? name : list + ',' + name
            	resolve(catList)
        	}, 200, returnVal)
    	})
    }
    
    function fn(list) {
    	return list + ',' + 555
    }
    
    async function render() {
        var a = await buildCatList('','Panther')
        var b = await buildCatList(a, 'Jaguar')
        var c = await buildCatList(b, 'Lion')
        var d = await fn(c)
        console.log(d)
    }
    
    render()
    
    // Panther,Jaguar,Lion,555
    
    
       コードは簡潔で明瞭で、非同期コードも「同期」コードの構造を持っています.