js處理異步請求進化論

場景描述javascript

一、 地獄回調java

二、 地獄回調優化編程

三、Promise數組

四、Generatorpromise

五、Asyncmarkdown

場景描述: 異步

咱們經常會遇到這樣的業務場景:後一步異步請求依賴前一步異步請求的結果,若是這樣的依賴層數比較多,那麼初學者很容易寫出地獄回調的代碼。async

如下代碼均以setTimeout模擬異步請求。異步編程


地獄回調函數

setTimeout(() => {
    console.log('step1');
    setTimeout(() => {
        console.log('step2');
        setTimeout(() => {
            console.log('step3');
        }, 1000);
    }, 1000);
}, 1000);
複製代碼

以上代碼看起來不利於閱讀和維護,咱們能夠稍加優化。

地獄回調優化

function step1() {
    setTimeout(() => {
        console.log('step1');
        step2('step1');
    }, 1000)
}
function step2(data) {
    setTimeout(() => {
        console.log('step2');
        step3('step2');
    }, 1000)
}
function step3(data) {
    setTimeout(() => {
        console.log('step3');
    }, 1000)
}
step1();
複製代碼

以上的代碼雖然看上去利於閱讀了,可是仍是沒有解決根本問題。而地獄回調的根本問題就是:

  1. 嵌套函數存在耦合性,一旦有所改動,就會牽一髮而動全身

  2. 嵌套函數一多,就很難處理錯誤

    固然,回調函數還存在着別的幾個缺點,好比不能使用try catch捕獲錯誤,不能直接return。


如何解決回調地獄呢?

  • 使用ES6中的Promise,Promise有三種狀態:pending/reslove/reject 。pending就是未決,resolve能夠理解爲成功,reject能夠理解爲拒絕。 同時Promise經常使用的三種方法:
    • then 表示異步成功執行後的數據狀態變爲reslove
    • catch 表示異步失敗後執行的數據狀態變爲reject
    • all表示把多個沒有關係的Promise封裝成一個Promise對象使用then返回一個數組數據。

下面一塊兒來看看如何使用Promise:

promise

var step1 = function () {
    return new Promise(function (resolve, reject) {
        let st = setTimeout(() => {
            resolve('step1');
        }, 1000);
    });
}

var step2 = function () {
    return new Promise(function (resolve, reject) {
        let st = setTimeout(() => {
            resolve('step2')
        }, 1000);
    });
}

var step3 = function () {
    return new Promise(function (resolve, reject) {
        let st = setTimeout(() => {
            resolve('step3')
        }, 1000);
    })
}
step1().then(function (data) {
    console.log(data);
    return step2();
}).then(data => {
    console.log(data);
    return step3();
}).then(data => {
    console.log(data);
})
複製代碼

  • Generator 函數是 ES6 提供的一種異步編程解決方案,語法行爲與傳統函數徹底不一樣。形式上,Generator 函數是一個普通函數,可是有兩個特徵:
    1. function關鍵字與函數名之間有一個星號(*);
    2. 函數體內部使用yield表達式,定義不一樣的內部狀態

Generator

var step1 = function () {
    return new Promise((resolve, reject) => {
        setTimeout(function () {
            resolve("step1");
        }, 1000);
    })
}
var step2 = function () {
    return new Promise((resolve, reject) => {
        setTimeout(function () {
            resolve("step2");
        }, 1000);
    })
}
var step3 = function () {
    return new Promise((resolve, reject) => {
        setTimeout(function () {
            resolve("step3");
        }, 1000);
    })
}
function* g() {
    yield step1();
    yield step2();
    yield step3();

}
var step = g();
step.next().value.then(data => {
    console.log(data);
    return step.next().value;
}).then(data => {
    console.log(data);
    return step.next().value;
}).then(data => {
    console.log(data);
});
複製代碼

  • 固然生成器不是最完美的,它的語法讓人難以理解,因此ES7推出了async/await (異步等待)。

async

var step1 = async function () {
    return new Promise(function (resolve, reject) {
        let st = setTimeout(() => {
            resolve('step1');
        }, 1000);
    });
}

var step2 = function () {
    return new Promise(function (resolve, reject) {
        let st = setTimeout(() => {
            resolve('step2')
        }, 1000);
    });
}

var step3 = function () {
    return new Promise(function (resolve, reject) {
        let st = setTimeout(() => {
            resolve('step3')
        }, 1000);
    })
}
async function test() {
    var data1 = await step1();
    console.log(data1);
    var data2 = await step2();
    console.log(data2);
    var data3 = await step3();
    console.log(data3)
}
test();
複製代碼

最後,期待你們一同交流,共同進步。

相關文章
相關標籤/搜索