javascript異步與promise

同期異步系列文章推薦
談一談javascript異步
javascript異步中的回調
javascript異步之Promise.all()、Promise.race()、Promise.finally()
javascript異步之Promise.resolve()、Promise.reject()
javascript異步之Promise then和catch
javascript異步之async(一)
javascript異步之async(二)
javascript異步實戰
javascript異步總結歸檔

我們說處理javascript異步最常用的方式就是通過回調函數,對於回調函數我們昨天對此做了介紹
簡單快速,
我們一般使用嵌套回調或者鏈式回調,會產生以下問題

  1. 當採用嵌套回調時,會導致層級太多,不利於維護
  2. 所以我們又採用了鏈式回調,對嵌套回調進行拆分,拆分後的函數間耦合度很高,
  3. 如果需要傳遞參數,函數之間的關聯性會更高,而且要對參數進行校驗以提高代碼的健壯性
  4. 如果將我們自己的回調函數傳遞給第三方插件或者庫,就要考慮一些不可控因素

    • 調用回調過早
    • 調用回調過晚(或不被調用)
    • 調用回調次數過多或者過少

promise的存在就是爲了解決以上問題
雖然我們日常寫回調函數不會有這麼嚴格的要求,但是如果不這樣去寫回調函數,就會存在隱患,當在團隊協作的時候,顯得編碼規範顯得尤爲重要

本文不重點介紹如何使用promise,重點介紹的是promise解決了哪些異步回調出現的問題。

什麼是promise

我們來看一個場景,有助於我們瞭解promise

設想一下這個場景,我去KFC,交給收銀員10元,下單買一個漢堡,下單付款。到這裏,我已經發出了一個請求(買漢堡),啓動了一次交易。
但是做漢堡需要時間,我不能馬上得到這個漢堡,收銀員給我一個收據來代替漢堡。到這裏,收據就是一個承諾(promise),保證我最後能得到漢堡。
所以我需要好好的保留的這個收據,對我來說,收據就是漢堡,雖然這張收據不能吃,我需要等待漢堡做好,等待收銀員叫號通知我
等待的過程中,我可以做些別的事情
收銀員終於叫到了我的號,我用收據換來了漢堡
當然還有一種情況,當我去櫃檯取漢堡的時候,收銀員告訴我漢堡賣光了,做漢堡的師傅受傷了等等原因,導致了我無法得到這個漢堡
雖然我有收據(承諾),但是可能得到漢堡(成功),可能得不到漢堡(失敗)
我由等待漢堡變成了等到或者等不到,這個過程不可逆,

上面很形象的介紹了promise,上面的等待漢堡和得到漢堡,漢堡賣光了,得不到漢堡,分別對應promise的三種狀態
三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)(一旦狀態改變,就不會再變)

回調函數調用過早

調用過早就是將異步函數作爲同步處理了,
我們之前說過,javascript以單線程同步的方式執行主線程,遇到異步會將異步函數放入到任務隊列中,
當主線程執行完畢,會循環執行任務隊列中的函數,也就是事件循環,直到任務隊列爲空。

事件循環和任務隊列

事件循環就像是一個遊樂場,玩過一個遊戲後,你需要重新排到隊尾才能再玩一次
任務隊列就是,在你玩過一個遊戲後,可以插隊接着玩

我們看一個栗子

    const promise = new Promise((resolve, reject) => {
      resolve("成功啦")
    });
    promise.then(res => {
      console.log(res);
      console.log("我是異步執行的");
    })
    console.log('我在主線程');

看下輸出,重點看輸出順序

//我在主線程
//成功啦
//我是異步執行的

直接手動是promise的狀態切爲成功狀態,console.log("我是異步執行的");這段代碼也是異步執行的
提供給then()的回調永遠都是異步執行的,所以promise中不會出現回調函數過早執行的情況

回調函數調用過晚或不被調用

回調函數調用過晚

回調函數調用過晚的處理原理和調用過早很類似,
在promise的then()中存放着異步函數,所有的異步都存在於js的任務隊列中,當js的主線程執行完畢後,會依次執行任務隊列中的內容,不會出現執行過晚的情況

回調函數不被調用

我們用栗子說話

    const promise = new Promise((resolve, reject) => resolve('成功啦'))
    promise.then(s => console.log(s));
    console.log('我在主線程');

成功狀態的輸出

//我在主線程
//成功啦

成功狀態下回調被調用
繼續看一下失敗的回調

    const promise = new Promise((resolve, reject) => reject('失敗啦'))
   promise.then(null, s => console.log(s));
   console.log('我在主線程');

失敗狀態的輸出

//我在主線程
//失敗啦

失敗狀態下回調被調用
所以說,不管是失敗還是成功,回調函數都會被調用

回調函數調用次數過多或者過少

調用次數過多

我們之前說了promise有三種狀態
pending(進行中)、fulfilled(已成功)和rejected(已失敗)狀態一旦狀態改變,就不會再變
一個栗子

    const promise = new Promise((resolve, reject) => {
      reject('失敗啦')
      resolve('成功啦')
    });
    promise.then(res => {
      console.log(`我是異步執行的成功:${res}`);
    },err=>{
      console.log(`我是異步執行的失敗:${err}`);
    }).catch(err => {
      console.log(err);
    })
    console.log('我在主線程');

輸出

//我在主線程
//我是異步執行的失敗:失敗啦

當狀態變爲失敗時,就不會再變爲成功,成功的函數也不會執行,反之亦然

調用次數過少

回調函數正常是調用一次,過少=>0次=>回調函數不被調用,上面剛剛討論過

原文鏈接

參考鏈接
JavaScript Promise 迷你書
Promise 對象
ES6 系列之我們來聊聊 Promise

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章