一、Promise
異步操作便瑟,解決 callback hell 問題
三種狀態(tài): pending, resolved, rejected
狀態(tài)的表現(xiàn)和變化康聂,pending ->resolved pending ->rejected,變化不可逆then 正常狀態(tài)返回 resolved 辑鲤,有報(bào)錯(cuò)則返回 rejected
catch 正常狀態(tài)返回 resolved 纹因,有報(bào)錯(cuò)則返回 rejected
二喷屋、 async 和 await
同步語法,消滅異步回調(diào)函數(shù)瞭恰,async/await只是一個(gè)語法糖
await 函數(shù)后面的都屬于回調(diào)-
async/await 與 promise 的關(guān)系
- 執(zhí)行async 函數(shù)屯曹,返回的是 promise 對(duì)象
- 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
借用雙越老師的一張圖具體講解恶耽,先來一個(gè)簡單版的:
- 將第一行代碼 console.log('Hi') 放入Call Stack(調(diào)用棧)
- 執(zhí)行,瀏覽器打印出 Hi
- 清空 Call Stack
- 將setTimeout 方法放入 Call Stack颜启,執(zhí)行發(fā)現(xiàn)這個(gè)是個(gè)異步函數(shù)偷俭,先推入 web API 清空 Call Stack
- 將最后一行代碼 console.log('Bye') 推入 Call Stack ,執(zhí)行缰盏,打印出 Bye涌萤,清空 Call Stack
- 此時(shí)所有同步代碼執(zhí)行完畢
- Event Loop 開始啟動(dòng),輪詢查找 Callback Queue里是否有可執(zhí)行的語句
- 時(shí)機(jī)到(定時(shí)乳规,網(wǎng)絡(luò)請(qǐng)求形葬,用戶操作等)合呐,將里面可以執(zhí)行的代碼推入 Callback Queue
- Event Loop 查到有可執(zhí)行語句暮的,將此語句推入 Call Stack ,執(zhí)行淌实,打印出 cb1冻辩,清空 Call Stack
- Event Loop 繼續(xù)輪詢查找(永動(dòng)機(jī))
四、宏任務(wù)和微任務(wù)
宏任務(wù):setTimeout拆祈, setInterval恨闪, Ajax,DOM 事件
微任務(wù):promise放坏,async/await
微任務(wù)比宏任務(wù)執(zhí)行時(shí)機(jī)要早
image.png
依然是雙越老師的圖咙咽,我們?cè)僦v一次升級(jí)版的瀏覽器執(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
- 此時(shí)同步代碼執(zhí)行完畢
- Event Loop 開始啟動(dòng)
- 開始執(zhí)行微任務(wù),將 micro task queue 的代碼推入 callback queue愚战,觸發(fā) Event Loop 將此代碼推入 Call Stack 娇唯,執(zhí)行,清空
- 微任務(wù)執(zhí)行完畢
- 嘗試 DOM 渲染
- 執(zhí)行宏任務(wù)寂玲,時(shí)機(jī)到時(shí)塔插,將 Web APIs 里的代碼推入 callback queue,觸發(fā) Event Loop 將此代碼推入 Call Stack 拓哟,執(zhí)行佑淀,清空
- Event Loop 繼續(xù)輪詢查找(永動(dòng)機(jī))
宏任務(wù)和微任務(wù)的區(qū)別
- 宏任務(wù): DOM 渲染后觸發(fā),由 ES6 語法規(guī)定(執(zhí)行前推入micro task queue)
- 微任務(wù): DOM 渲染前觸發(fā)彰檬,由瀏覽器規(guī)定的(執(zhí)行前推入 Web APIs棧中)
四伸刃、for of
一個(gè)異步遍歷方法,話不多說逢倍,直接貼代碼
// 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)
}
})()
手寫一個(gè) ajax 方法
// 手寫一個(gè) 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)
幾個(gè)方面來解答:
- 瀏覽器同源策略和跨域
- 哪些 html 標(biāo)簽可以繞過跨域(Image script)
- 利用 script 封裝成 jsonp