異步!異步!異步!

1.同步和異步

1.1先說個傻子的故事

有個傻子,第一次用某雷下載大片,就是大人看的片,咳咳咳。。。
某雷告訴他,下載時間要倆小時,傻子心想,要倆小時吶,我第一次用某雷,我得盯着它下載,啥也不能幹
因而傻子就幹瞪着電腦,等着片下完,這倆小時,傻子啥也沒幹
後來,傻子變聰明瞭,他想,反正某雷在幫他下載,這倆小時,他徹底能夠乾乾其餘事情啊,好比學學計算機知識呀等等
等某雷下完了,再回來看唄
因而傻子潛心研究計算機知識,直到有一天他看到了有關於異步的知識,忽然間明白了

原來他等待某雷下完,啥也不幹的過程就叫作同步
後來他在某雷下載過程當中自學計算機知識的過程就叫作異步面試

1.2 同步與異步的概念

同步
英文:Synchronization
wiki解釋:指在一個系統中所發生的事件(event),之間進行協調,在時間上出現一致性與統一化的現象。
是否是很難理解?
其實就是代碼要等待到結果,才能繼續進行【你能夠理解爲同步阻塞了代碼繼續執行】segmentfault

異步
英文:Asynchronization【在同步前面加了個A】
wiki解釋就不貼了,有興趣的朋友能夠本身搜索看一下,反正我看的也挺頭疼
其實就是代碼不用等待到結果,就能繼續進行【你能夠理解爲異步不阻塞代碼繼續執行】
啥意思咧,讓咱們看個你們都見過的例子promise

function wait() {
    setTimeout(() => console.log(this), 3000)
}

wait() // 三秒鐘後,獲得結果
console.log(1) // 若是沒有異步的話,我得等三秒鐘才能執行,因此,感謝異步

2.常見的異步問題

2.1圖片加載問題

// 前提條件:用戶的瀏覽器第一次請求這個圖片,也就是用戶的瀏覽器未緩存
document.getElementsByTagNames('img')[0].width // 寬度爲 0

爲何width會爲0呢?
由於js運行的時候,img並無下載完畢瀏覽器

解決方案緩存

let imgNode = document.getElementsByTagName('img')[0]
imgNode.addEventListener('onload',function () {
    console.log(this.width)
})

2.2 面試題常考的異步問題

// 假設有5個li
let liList = document.querySelectorAll('li')
for (var i = 0; i < liList.length; i++) {
    liList[i].onclick = function () {
        console.log(i) // 5 5 5 5 5
    }
}

爲何呢?
由於onclick事件是異步處理的,用戶觸發onclick事件時,循環早已結束,此時的i是5異步

解決方案一【當即執行函數建立獨立做用域】async

// 假設有5個li
let liList = document.querySelectorAll('li')
for (var i = 0; i < liList.length; i++) {
    !(function (j) {
        liList[j].onclick = function () {
            console.log(j) // 5 5 5 5 5
        }
    })(i)
}

解決方案二【使用let】函數

// 假設有5個li
let liList = document.querySelectorAll('li')
for (let i = 0; i < liList.length; i++) {
    liList[i].onclick = function () {
        console.log(i) // 5 5 5 5 5
    }
}

3.拿到異步結果的方式 —— 回調

請見回調是個什麼鬼?this

4.Promise

請見淺析Promisecode

5.async / await 語句

5.1 粗略瞭解await

mdn解釋:await 操做符用於等待一個Promise 對象。它只能在異步函數 async function 中使用

可是await究竟作了什麼事情呢?
let setPromise = function () {
    return new Promise((resolve, reject) => {
        // 你的異步代碼
        setTimeout(() => {
            resolve('success')
        }, 10000)
    })
}
let result = await setPromise()

若是你這個時候在控制檯不斷輸入result。
控制檯會不斷地報錯
控制檯報錯:result is not defined
直到10s後,才能成功

爲啥報錯呢?命名let result了呀
由於await在等待setPromise()完成後,纔會執行let result =
也就是說await 讓前面的 let 和 = 異步了

可能你會問:
這樣一搞,result也異步了,那我豈不是還要回調?

那麼再來看下一個問題
let setPromise = function () {
    return new Promise((resolve, reject) => {
        // 你的異步代碼
        setTimeout(() => {
            resolve('success')
        }, 10000)
    })
}
let result = await setPromise()
console.log(1) // 請問這句代碼是在10秒後被執行,仍是當即執行?

答案:10s後執行

5.2 因此await究竟能幹嗎

await改變了整個代碼的執行順序.
它可讓你用同步寫代碼的方式去寫異步代碼

5.3 那麼async又是幹啥的呢?

若是你在一個函數內使用了await,那麼你最好在一個函數的前面加上async

let setPromise = function () {
    return new Promise((resolve, reject) => {
        // 你的異步代碼
        setTimeout(() => {
            resolve('success')
        }, 2000)
    })
}
function test() {
    return result = await setPromise()
}
console.log(3)

控制檯直接會報錯:Uncaught SyntaxError: await is only valid in async function
啥意思咧 —— await只容許在 async function 內使用
也就是說,要在函數聲明的時候就加上 async

async function test() {
    let result = await setPromise()
}

5.4 Promise異步操做失敗的狀況

let setPromise = function () {
    return new Promise((resolve, reject) => {
        // 你的異步代碼
        setTimeout(() => {
            reject.call(undefined)
        }, 2000)
    })
}
let result = await setPromise()
console.log(result)
// 瀏覽器又報錯了 Uncaught (in promise) undefined

由於沒有then/catch來處理Promise異步操做失敗的結果
因此咱們此次使用try...catch...語句

let setPromise = function () {
    return new Promise((resolve, reject) => {
        // 你的異步代碼
        setTimeout(() => {
            reject.call(undefined)
        }, 2000)
    })
}
try {
    let result = await setPromise()
    console.log(result)
} catch(rejected) {
    // 觸發這一句
    console.log('error')
}
相關文章
相關標籤/搜索