新手不太注意的promise細節和eventloop

這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰node

基礎用法

const p=new Promise((resolve,reject)=>{
    if(...){
        reject(new Error())
    }
    resolve(100)
})

p.then((val)=>{
    console.log(val) // 100
},(err)=>{
    console.log('rejected',err)
})
複製代碼

ajax如何封裝爲promise

function ajax(url){
    return new Promise((res,rej)=>{
        const xhr=new XMLHttpRequest()
        xhr.open('GET',url)
        xhr.onload=function(){
            if(this.status===200){
                resolve(this.response)
            }else{
                reject(new Error(this.statusText))
            }
        }
        xhr.send()
    })
}

ajax('api/a/b.json').then((res)=>{
    console.log(res)
},(err)=>{
    console.log(err)
})
複製代碼

promise鏈式調用

每個then方法都是在爲上一個then返回狀態明確的回調。Promise的then方法會返回一個全新的promise對象。then方法裏,若是返回一個肯定的簡單值如'aa',能夠視爲return Promise.resolve('aa')。若是沒有返回值則視爲返回Promise.resolve(undefined)。後面的then方法就是在爲上一個then返回的Promise註冊回調,前面的then方法中回調函數的返回值會做爲後面的then方法回調的參數,若是回調中返回的是promise對象,後面的then方法的回調會等待它的決議。面試

promise異常處理

then方法中的異常捕獲和promise.catch有很大不一樣,看下面代碼ajax

const p=()=>=new Promise(....)

p() //1
.then(()=>{},(err)=>{
// 只能捕獲到1處的異常
})

p()//1
.then(()=>{}) //2
.catch(err=>{
// 一、2處的異常均可以捕獲
})
複製代碼

promise上的任何異常都會向後傳遞直至捕獲。json

全局捕獲未定義異常

能夠註冊unhandledrejection事件來捕獲未被定義的異常api

window.addEventListener('unhandledrejection',event=>{
    const {reason,promise}=event
    console.log(reason,promise)
    // reason失敗緣由,promise失敗對象
    event.preventDefault();
},false)
複製代碼

同理,對於node環境:promise

process.addEventListener('unhandledrejection',(reason,promise)=>{
    console.log(reason,promise)
    // reason失敗緣由,promise失敗對象
})
複製代碼

Promise靜態方法

Promise.resolve

傳入promise對象

const promise1=ajax('/api/....')
const promise2=Promise.resolve(promise)
promise1===promise2 // true
複製代碼

傳入thenable對象

Promise.resolve({
    then:(onFullfilled,onRejected)=>{
        onFullfilled('foo')
    }
})
.then(val=>{
    console.log(val) // foo
})
複製代碼

Promise.reject

Promise.all(Array)

Promise.all(Array)等待全部的任務都成功結束纔會成功結束,只要有一個任務失敗,這個promise就會以失敗結束markdown

Promise.race(Array)

競爭態,只會返回第一個結束的任務。異步

promise執行時序(宏任務與微任務)

宏任務能夠選擇做爲一個新的宏任務進到隊列中排隊,也能夠做爲當前任務的微任務,直接在當前任務結束事後當即執行,而不是到整個消息隊列中從新排隊。目前大多數異步調用都是做爲宏任務執行函數

宏任務:setTimeout、setInterval、requestAnimationFrameoop

微任務:promise回調,MutationObserver,process.nextTick

一道面試題:

setTimeout(_ => console.log(4))

new Promise(resolve => {
  resolve()
  console.log(1)
}).then(_ => {
  console.log(3)
})

console.log(2)
複製代碼

打印 一、二、三、4。4先進入消息隊列(宏任務),promise實例化是同步代碼,因此按照順序先執行1,promise的回調3是異步放入消息隊列(微任務),以後同步下來打印2.eventloop啓動,先執行微任務,打印3,執行宏任務打印4.

eventloop代碼表示

const macroTaskList = [
  ['task1'],
  ['task2', 'task3'],
  ['task4'],
]                                                                                                           

for (let macroIndex = 0; macroIndex < macroTaskList.length; macroIndex++) {
  const microTaskList = macroTaskList[macroIndex]
  
  for (let microIndex = 0; microIndex < microTaskList.length; microIndex++) {
    const microTask = microTaskList[microIndex]

    // 添加一個微任務
    if (microIndex === 1) microTaskList.push('special micro task')
    
    // 執行任務
    console.log(microTask)
  }

  // 添加一個宏任務
  if (macroIndex === 2) macroTaskList.push(['special macro task'])
}

// > task1
// > task2
// > task3
// > special micro task
// > task4
// > special macro task

複製代碼
相關文章
相關標籤/搜索