可修改下面的 aa()
函數,目的是在一秒後用 console.log()
輸出 want-value
java
function aa() { setTimeout(function() { return "want-value"; }, 1000); }
可是,有額外要求:面試
aa()
函數能夠隨意修改,可是不能有 console.log()
console.log()
語句裏不能有 setTimeout
包裹也許這是個面試題,管它呢。問題的主要目的是考察對異步調用執行結果的處理,既然是異步調用,那麼不可能同步等待異步結果,結果必定是異步的segmentfault
setTimeout()
常常用來模擬異步操做。最先,異步是經過回調來通知(調用)處理程序處理結果的異步
function aa(callback) { setTimeout(function() { if (typeof callback === "function") { callback("want-value"); } }, 1000); } aa(function(v) { console.log(v); });
不過回調在用於稍大型一點的異步應用時,容易出現多層嵌套,因此以後提出了一些對其進行「扁平」化,這一部分能夠參考閒談異步調用「扁平」化。固然 Promise 是很是流行的一種方法,並最終被 ES6 採納。用 Promise 實現以下:async
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()
對其進行處理。code
這裏須要注意的是 await
只能在 async
方法中使用,因此爲了使用 await
必須定義一個 async
的 main 方法,並在全局做用域中調用。因爲 main 方法是異步的(申明爲 async),因此若是 main()
調用以後還有其它語句,好比 console.log("hello")
,那麼這一句話會先執行。ip
async/await 語法讓異步調用寫起來像寫同步代碼,在編寫代碼的時候,能夠避免邏輯跳躍,寫起來會更輕鬆。(參考:從地獄到天堂,Node 回調向 async/await 轉變)作用域
固然,定義 main()
再調用 main()
這部分能夠用 IIFE 封裝一下,
(async () => { const v = await aa(); console.log(v); })();