視訊課程-迴圈中呼叫非同步方法

冰山工作室發表於2019-03-20

課程視訊--for迴圈裡的setTimeout

一個普通的for迴圈裡面log一下 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說一下吧。

關於我們

視訊課程線上觀看-----傳送門

視訊課程網盤地址-----傳送門 提取碼: ifv9

冰山社團官網地址-----傳送門

如果觀看視訊或文件後,你覺得有些收穫,願意加入冰山社團與我們一同成長,請進入我們的官網,點選冰山社團,加入我們~

相關文章