天天看點

從小小題目逐漸走進 JavaScript 異步調用

問題

原題來自 @若澤[wangwenlin] 的提問。

可修改下面的

aa()

函數,目的是在一秒後用

console.log()

輸出

want-value

function aa() {
    setTimeout(function() {
        return "want-value";
    }, 1000);
}           

但是,有額外要求:

  1. aa()

    函數可以随意修改,但是不能有

    console.log()

  2. 執行

    console.log()

    語句裡不能有

    setTimeout

    包裹

解答

也許這是個面試題,管它呢。問題的主要目的是考察對異步調用執行結果的處理,既然是異步調用,那麼不可能同步等待異步結果,結果一定是異步的

setTimeout()

經常用來模拟異步操作。最早,異步是通過回調來通知(調用)處理程式處理結果的

function aa(callback) {
    setTimeout(function() {
        if (typeof callback === "function") {
            callback("want-value");
        }
    }, 1000);
}

aa(function(v) {
    console.log(v);
});           

不過回調在用于稍大型一點的異步應用時,容易出現多層嵌套,是以之後提出了一些對其進行“扁平”化,這一部分可以參考閑談異步調用“扁平”化。當然 Promise 是非常流行的一種方法,并最終被 ES6 采納。用 Promise 實作如下:

function aa() {
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("want-value");
        }, 1000);
    });
}

aa().then(v => console.log(v));           

就這個例子來說,它和前面回調的例子大同小異。不過它會引出目前更推薦的一種方法——async/await,從 ES2017 開始支援:

function aa() {
    return new Promise(resolve => {
        setTimeout(function() {
            resolve("want-value");
        }, 1000);
    });
}

async function main() {
    const v = await aa();
    console.log(v);
}

main();           

aa()

的定義與 Promise 方法中的定義是一樣的,但是在調用的時候,使用了

await

,異步等待,等待到異步的結果之後,再使用

console.log()

對其進行處理。

(async () => {
    const v = await aa();
    console.log(v);
})();           

繼續閱讀