一、Promise
異步操作,解決 callback hell 問題
三種狀態(tài): pending, resolved, rejected
狀態(tài)的表現(xiàn)和變化,pending ->resolved pending ->rejected,變化不可逆then 正常狀態(tài)返回 resolved ,有報錯則返回 rejected
catch 正常狀態(tài)返回 resolved ,有報錯則返回 rejected
二、 async 和 await
同步語法,消滅異步回調(diào)函數(shù),async/await只是一個語法糖
await 函數(shù)后面的都屬于回調(diào)-
async/await 與 promise 的關(guān)系
- 執(zhí)行async 函數(shù),返回的是 promise 對象
- await 相當(dāng)于 promise 的 then
- try...catch 可以捕獲異常,代替了 promise 的 catch
async function fn(){
return 100
}
(async function(){
const a = fn // 返回上面的函數(shù)
const b = await fn() // 返回 100
})()
三、event loop

image.png
借用雙越老師的一張圖具體講解,先來一個簡單版的:
- 將第一行代碼 console.log('Hi') 放入Call Stack(調(diào)用棧)
- 執(zhí)行,瀏覽器打印出 Hi
- 清空 Call Stack
- 將setTimeout 方法放入 Call Stack,執(zhí)行發(fā)現(xiàn)這個是個異步函數(shù),先推入 web API 清空 Call Stack
- 將最后一行代碼 console.log('Bye') 推入 Call Stack ,執(zhí)行,打印出 Bye,清空 Call Stack
- 此時所有同步代碼執(zhí)行完畢
- Event Loop 開始啟動,輪詢查找 Callback Queue里是否有可執(zhí)行的語句
- 時機到(定時,網(wǎng)絡(luò)請求,用戶操作等),將里面可以執(zhí)行的代碼推入 Callback Queue
- Event Loop 查到有可執(zhí)行語句,將此語句推入 Call Stack ,執(zhí)行,打印出 cb1,清空 Call Stack
- Event Loop 繼續(xù)輪詢查找(永動機)
四、宏任務(wù)和微任務(wù)
宏任務(wù):setTimeout, setInterval, Ajax,DOM 事件
微任務(wù):promise,async/await
微任務(wù)比宏任務(wù)執(zhí)行時機要早

image.png
依然是雙越老師的圖,我們再講一次升級版的瀏覽器執(zhí)行方式:
- 首先依然是按照代碼順序,將代碼推入 Call Stack
- 同步代碼,執(zhí)行,清空 Call Stack
- Call Stack 中發(fā)現(xiàn)代碼是 promise 或者 async/await 代碼,執(zhí)行,將回調(diào)代碼放入micro task queue
- Call Stack 中發(fā)現(xiàn)代碼是 setTimeout 或者 DOM 操作等等,執(zhí)行,將回調(diào)代碼放入 web APIs
- 此時同步代碼執(zhí)行完畢
- Event Loop 開始啟動
- 開始執(zhí)行微任務(wù),將 micro task queue 的代碼推入 callback queue,觸發(fā) Event Loop 將此代碼推入 Call Stack ,執(zhí)行,清空
- 微任務(wù)執(zhí)行完畢
- 嘗試 DOM 渲染
- 執(zhí)行宏任務(wù),時機到時,將 Web APIs 里的代碼推入 callback queue,觸發(fā) Event Loop 將此代碼推入 Call Stack ,執(zhí)行,清空
- Event Loop 繼續(xù)輪詢查找(永動機)
宏任務(wù)和微任務(wù)的區(qū)別
- 宏任務(wù): DOM 渲染后觸發(fā),由 ES6 語法規(guī)定(執(zhí)行前推入micro task queue)
- 微任務(wù): DOM 渲染前觸發(fā),由瀏覽器規(guī)定的(執(zhí)行前推入 Web APIs棧中)
四、for of
一個異步遍歷方法,話不多說,直接貼代碼
// for of
function muti(num) {
const a = new Promise(resolve => {
setTimeout(() => {
resolve(num * num)
}, 1000)
})
return a;
}
let arr = [2, 4, 6]
!(async function(){
for(let i of arr) {
const res = await muti(i)
console.log(res)
}
})()
手寫一個 ajax 方法
// 手寫一個 ajax 方法
function ajax(url){
const p = new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET',url,true)
xhr.onreadystatechange = function () {
if(xhr.readyState === 4) {
if(xhr.status === 200) {
console.log(xhr);
resolve(JSON.parse(xhr.response))
} else {
reject(new Error('404 not found'))
}
}
}
xhr.send(null)
})
return p
}
// 試一下
const url = 'http://demo.mall.10010.com:8104/scaffold-app/scaffold/queryPagealiasProData?page_alias=two-in-one'
ajax(url).then((res) => {
console.log(res);
}).catch(err => console.log(err))
手寫深度比較
// 手寫深度比較
function isObject(obj) {
return typeof obj === 'object' && obj != null
}
function isEqual (obj1, obj2) {
if(!isObject(obj1) || !isObject(obj2)) {
return obj1 === obj2
}
if (obj1 === obj2) {
return true;
}
const obj1Key = Object.keys(obj1)
const obj2Key = Object.keys(obj2)
if (obj1Key.length != obj2Key.length) {
return false
}
for(let key in obj1) {
const res = isEqual(obj1[key], obj2[key])
if(!res){
return false
}
}
return true
}
jsonp 原理(不是真正的 ajax)
幾個方面來解答:
- 瀏覽器同源策略和跨域
- 哪些 html 標(biāo)簽可以繞過跨域(Image script)
- 利用 script 封裝成 jsonp