回调地狱的解决方式

什么是回调地狱

    异步的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 拆分的方式其实仅仅只是拆分代码块,时常会不利于后续维护

  1. 通过 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, 'Janguar')
})

// Panther,Janguar,Lion

Promise函数虽然改变了之前回调地狱的写法,但是在根本上还是函数套函数,看起来不是那么的美观

  1. 通过Generator函数暂停执行的效果方式
function getPanther(next) {
    console.log('Panther')
    next()
}

function getJaguar(next) {
    console.log('Jaguar')
    next()
}

function getLion(next) {
    console.log('Lion')
    next()
}

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

//流程控制
function run(fn){
    const gen = fn()     // 调用 Generator 函数,返回一个遍历器对象 (Iterator)
    function next() {
        const result = gen.next()  // 每次调用遍历器对象的 next() 方法,就会返回一个有着 value 和 done 两个属性的对象
        if (result.done) return   // 如果 result.done 的值等于 true 就结束
        result.value(next)
		// result.value 就是 yield 返回的值,是各个函数(方法)
        // next作为入参,即本函数(方法)执行后,执行下一函数(方法)
    }
    next()   //  这个方法被多次调用
}

run(buildCatList)   // 开始执行

// Panther
// Jaguar
// Lion

通过generator虽然能提供较好的语法结构,但是毕竟generator与yield的语境用在这里多少还有些不太贴切

  1. 通过ES8的异步函数 async / await
async function render() {
	await getPanther('Panther')
	await getJaguar('Jaguar')
	await getLion('Lion')
}
render()

function getPanther(name) {
    console.log(name)
}

function getJaguar(name) {
    console.log(name)
}

function getLion(name) {
    console.log(name)
}

// Panther
// Jaguar
// Lion

代码简洁清晰,异步代码也具有了“同步”代码的结构

猜你喜欢

转载自blog.csdn.net/fu983531588/article/details/89476190