迴圈中呼叫非同步方法
最近遇到一道比較有趣的面試題,題目很簡單但是涉及到了很多小的知識點,還蠻有意思的。
一個普通的for迴圈輸出i
// 正常寫一個for迴圈輸出i for (var i = 0; i < 5; i++) { console.log(i); } console.log(i);
假設你是一個面試者,你說說這幾行程式碼會輸出什麼?,你的內心活動會不會是“這特麼不就是一個迴圈嗎?面試官既然這麼問老子(他還笑肯定不是好東西,肯定有陷阱),好好想一下,這好像和我看的那個閉包的題很像啊,這面試官是不是沒寫完啊?怎麼辦。”
如果稍微改動一些尼,輸出結果又是什麼?
for迴圈中有一個定時器
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(new Date, i); }1000 * i); } console.log(new Date, i);
稍微加了點料(setTimeout)後,是不是看到這道題就舒服了,會不會想“’這不是老子背的最多的閉包問題麼,想一哈,setTimeout是會延遲執行的所以外面的log會先執行,i是用var宣告的,所以會變數提升,for迴圈裡i最後執行完i++,i變成了5,沒錯了,老子這題得分了”。
閉包解決。
// 閉包 for (var i = 0; i < 5; i++) { ~function (j) { setTimeout(function () { console.log(new Date, j); }, 1000 * j); }(i); }
順著上一個程式想“是不是還可以昇華一下,我還能執行出來0 1 2 3 4”
實作
var roles = ['角色1', '角色2', '角色3']; var arrayTest = []; for (var i = 0; i < roles.length; i++) { !function (i) { $.get('https://www.baidu.com', { role: roles[i] }, function (res) { console.log(i); arrayTest[i] = i + roles[i] + res; }) }(i); }
如果你登入一個後臺系統,這個賬號下有不同角色(角色不固定,後期可能增加),傳不同角色進行ajax請求得到相應渲染頁面的資料,但是這個介面只接收一個角色引數, 那我們應該怎麼按我們想要的順序獲取資料然後渲染頁面?
es6
const tasks = []; for (var i = 0; i < 5; i++) { ((j) => { tasks.push(new Promise((resolve) => { setTimeout(() => { console.log(new Date, j); resolve(); }, 1000 * j); // 定時器的超時時間逐步增加 })); })(i); } Promise.all(tasks).then(() => { setTimeout(() => { console.log(new Date, i); }, 1000); });
當你前面所有問題都順利的回答完了,你想沒想過可能還有20%的人可以回答到你這種程度,怎麼能變現的比他們牛逼一點尼?你可以考慮使用一下promise
setTimeout和promise優先順序
setTimeout(function () { console.log(1) }, 0); new Promise(function executor(resolve) { console.log(2); for (var i = 0; i < 10000; i++) { i == 9999 && resolve(); } console.log(3); }).then(function () { console.log(4); }); console.log(5);
“這道題應該考察我 JavaScript 的執行機制的,讓我理一下思路。
首先先碰到一個 setTimeout,於是會先設定一個定時,在定時結束後將傳遞這個函式放到任務佇列裡面,因此開始肯定不會輸出 1 。
然後是一個 Promise,裡面的函式是直接執行的,因此應該直接輸出 2 3 。
然後,Promise 的 then 應當會放到當前 tick 的最後,但是還是在當前 tick 中。
因此,應當先輸出 5,然後再輸出 4 。
最後在到下一個 tick,就是 1 。
2 3 5 4 1”
es7
const sleep = (timeountMS) => new Promise((resolve) => { setTimeout(resolve, timeountMS); }); (async () => { // 宣告即執行的 async 函式表示式 for (var i = 0; i < 5; i++) { await sleep(1000); console.log(new Date, i); } await sleep(1000); console.log(new Date, i); })();
要是想給面試官留一個關注新技術的更牛逼印象,那就用es7說一下吧。
原始高清視訊下載
QQ答疑交流群:
600633658