[重學前端基礎] Promise的時序問題&JS執行機制

前言

真的掌握了Promise的用法嗎?回顧一下Promise的特色,而後練習檢測一下吧。promise

Promise的特色

  • Promise構造函數是同步的,promise.then()中的函數是異步的
  • Promise只能從pending->resolve或pending->reject,狀態一但改變就不能再變
  • Promise.then、Promise.catch中不能return promise對象自己
  • Promise.then中必須是函數

Practice 1:瀏覽器

const promise3 = new Promise((r, j) => {
  r('success')
  j('error')
  r('success2')
})

promise3
  .then(res => {
    console.log('then:', res)
  })
  .catch(err => {
    console.log('error:', err)
  })
  
  //success

狀態一旦改變就不能再變異步

Practice 2:函數

Promise.resolve(1)
  .then(res => {
    console.log(res)
    return 2
  })
  .catch(err => {
    console.log(err)
    return 3
  })
  .then(res => {
    console.log(res)
  })
  
  // 1
  // 2

鏈式調用,then()中return的結果正常狀況下會傳遞給後面的then()中的回調函數oop

Promise.resolve(1)
  .then(res => {
    console.log(res)
    return new Error('error')
  })
  .then(res => {
    console.log(res)
  })
  .catch(err => {
    console.log(('error', err))
    return 3
  })

return error對象時也不會被catch捕獲,除非throw 一個error對象或者return Promise.reject()spa

new Promise((r, j) => {
  j('failed')
})
  .then(
    function success(res) {
      return res
    },
    function failed(err) {
      console.log('failed:', err)
    }
  )
  .then(res => {
    console.log(res)
  })
  .catch(err => {
    console.log('catch:', err)
    return 3
  })
  
  //failed: failed

then(resolve, reject).catch()線程

catch是then的第二個參數的簡寫,reject捕獲上一個函數的錯誤,這個時候catch捕獲不到code

new Promise((r, j) => {
  r('success')
})
  .then(
    function success(res) {
      throw new Error('error')
      return res
    },
    function failed(err) {
      console.log('failed:', err)
    }
  )
  .then(res => {
    console.log(res)
  })
  .catch(err => {
    console.log('catch:', err)
    return 3
  })
  
  //catch: Error: error

若是是then中的第一個回調函數拋出錯誤,會被catch捕獲cdn

Practice 3:對象

new Promise((r, j)=> {
 console.log(1)
 r()
 console.log(2)
}).then(()=> {
 console.log(3)
})
console.log(4)

//1 2 4 3
const promise1 = new Promise((r, s) => {
  setTimeout(() => {
    console.log('success')
    r('success')
  }, 1000)
})

const promise2 = promise1.then(() => {
  throw new Error('error!!')
})

console.log('promise1:', promise1)
console.log('promise2:', promise2)

setTimeout(() => {
  console.log('promise1:', promise1)
  console.log('promise2:', promise2)
}, 2000)

作對了嗎?若是錯了,回顧下Js的執行機制吧。

回顧下Js的事件循環

Js執行機制是事件循環,Js是單線程的語言,執行多個任務時須要按順序執行。Js的任務分爲如下幾類:

  • 廣義上Js任務分爲:同步任務和異步任務。
  • 狹義上Js任務分爲:宏任務(setTimeout、setInterval、script)和微任務(promise.then、promise.nextTick)(任務指的是這些方法裏面的回調函數)。**

當任務進入執行棧時,首先會判斷任務是同步的仍是異步的,同步的任務會被加入到主線程,異步的任務會被加入到event table,註冊函數;當異步任務完成返回結果時,event table會將函數移入到event queue(任務隊列),這個任務隊列中包含了2種任務:微任務和宏任務。

當Js執行任務時,首先將主線程的任務執行完,而後再將任務隊列中的任務加入到主線程中執行;這個過程當中首先會將任務隊列中的微任務加入到主線程中執行,執行完而後再取任務隊列中的宏任務到主線程執行,執行完再進入下一個循環,依此類推...

process.nextTick(() => {
    console.log('nextTick')
})
new Promise((r, s) => {
    console.log('promise')
    r()
}).then(() => {
    console.log('then')
})

setImmediate(() => {
    console.log('immediate')
})
console.log('end')

promise
end
nextTick
then
immediate

最後檢驗本身是否掌握的一個例子:

console.log('1');

setTimeout(function() {
    console.log('2');
    process.nextTick(function() {
        console.log('3');
    })
    new Promise(function(resolve) {
        console.log('4');
        resolve();
    }).then(function() {
        console.log('5')
    })
})
process.nextTick(function() {
    console.log('6');
})
new Promise(function(resolve) {
    console.log('7');
    resolve();
}).then(function() {
    console.log('8')
})

setTimeout(function() {
    console.log('9');
    process.nextTick(function() {
        console.log('10');
    })
    new Promise(function(resolve) {
        console.log('11');
        resolve();
    }).then(function() {
        console.log('12')
    })
})

1 7 6 8 2 4 9 11 3 10 5 12

作對了嗎?

注意:
Node中的process.nextTick獨立於事件循環以外, 優先級高於其餘微任務如: then()。

能夠參考:瀏覽器與Node的事件循環(Event Loop)有何區別

相關文章
相關標籤/搜索