色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

Promise規范與原理解析

OSC開源社區 ? 來源:OSC開源社區 ? 2023-12-05 15:49 ? 次閱讀

摘要

Promise 對象用于清晰的處理異步任務的完成,返回最終的結果值,本次分享主要介紹 Promise 的基本屬性以及 Promise 內部的基礎實現,能夠幫我們更明確使用場景、更快速定位問題。

Promise 出現的原因

首先我們先來看一段代碼:異步請求的層層嵌套
function fn1(params) {
  const xmlHttp = new XMLHttpRequest();
  xmlHttp.onreadystatechange = function(){
    if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
      const fn1Data = {name: 'fn1'}
      console.log(fn1Data, 'fn1Data');
      // 請求2
      (function fn2() {
        xmlHttp.onreadystatechange = function(){
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
          const fn2Data = {name: `${fn1Data.name}-fn2`}
          console.log(fn2Data, 'fn2Data');
          // 請求3
          (function fn2() {
            xmlHttp.onreadystatechange = function(){
            if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
              const fn3Data = {name: `${fn2Data.name}-fn3`}
              console.log(fn3Data, 'fn3Data');
            }
          }
          xmlHttp.open("GET","https://v0.yiketianqi.com/api?unescape=1&version=v61", true);
          xmlHttp.send();
          })()
        }
      }
      xmlHttp.open("GET","https://v0.yiketianqi.com/api?unescape=1&version=v61", true);
      xmlHttp.send();
      })()
    }
  }
  xmlHttp.open("GET","https://v0.yiketianqi.com/api?unescape=1&version=v61", true);
  xmlHttp.send();
}

fn1()

或者我們可以將上面的代碼優化為下面這樣

function fn1(params) {
  console.log(`我是fn1,我在函數${params}中執行!!!`);
}
  
function fn2(params) {
  try {
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function(){
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        console.log(`我是fn2,我在函數${params}中執行!!!結果是:`,params.data);
        fn1('fn2')
      }
    }
    xmlHttp.open("GET","https://v0.yiketianqi.com/api?unescape=1&version=v61", true);
    xmlHttp.send();
  } catch (error) {
    console.error(error);
  }
}
  
function fn3() {
  try {
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function(){
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
          console.log('fn3請求已完成');
          fn2('fn3')
      }
    }
    xmlHttp.open("GET","https://v0.yiketianqi.com/api?unescape=1&version=v61", true);
    xmlHttp.send();
    console.log('我是f3函數呀');
  } catch (error) {
    console.error(error);
  }
}
  
fn3()

由上面的兩種寫法的請求可見,在 promise 之前,為了進行多個異步請求并且依賴上一個異步請求的結果時,我們必須進行層層嵌套,大多數情況下,我們又對異步結果進行數據處理,這樣使得我們的代碼非常難看,并且難以維護,這就形成了回調地獄,由此 Promise 開始出現了。回調地獄缺點
  • 代碼臃腫

  • 可讀性差

  • 耦合性高

  • 不好進行異常處理

Promise 的基本概念

含義

  1. ES6 將其寫進了語言標準里統一了用法,是一個構造函數,用來生成 Promise 實例

  2. 參數為一個執行器函數 (執行器函數是立即執行的), 該函數有兩個函數作為參數,第一個參數是成功時的回調,第二個參數是失敗時的回調

  3. 函數的方法有 resolve (可以處理成功和失敗)、reject (只處理失敗)、all 等方法

  4. then、catch、finally 方法為 Promise 實例上的方法

狀態

  1. pending --- 等待狀態

  2. Fulfilled --- 執行狀態 (resolve 回調函數,then)

  3. Rejected --- 拒絕狀態 (reject 回調函數,catch)

  4. 狀態一旦改變就不會再變,狀態只可能是兩種改變,從 pending->Fulfilled,pending->Rejected

  5. 有兩個關鍵的屬性:PromiseState --- 狀態改變,PromiseResult --- 結果數據改變

const p1 = Promise.resolve(64)
const p2 = Promise.reject('我錯了')
const p3 = Promise.then()
const p4 = Promise.catch()

// 狀態改變PromiseState 結果改變PromiseResult
console.log(new Promise(()=>{}), 'Promise');  // PromiseState='pending' PromiseResult=undefined
console.log(p1,'p1');  // PromiseState='Fulfilled' PromiseResult=64
console.log(p2,'p2');  // PromiseState="Rejected" PromiseResult='我錯了'
console.log(p3, 'p3'); // then為實例上的方法,報錯
console.log(p4, 'p4');  // catch為實例上的方法,報錯
a047ff72-9296-11ee-939d-92fbcf53809c.png?特點1.錯誤信息清晰定位:可以在外層捕獲異常信息(網絡錯誤、語法錯誤都可以捕獲),有 “冒泡” 性質,會一直向后傳遞,直到被捕獲,所以在最后寫一個 catch 就可以了2.鏈式調用:每一個 then 和 catch 都會返回一個新的 Promise,把結果傳遞到下一個 then/catch 中,因此可以進行鏈式調用 --- 代碼簡潔清晰

結果由什么決定

resolve

  1. 如果傳遞的參數是非 Promise 類型的對象,則返回的結果是成功狀態的 Promise 對象,進入下一個 then 里面

  2. 如果傳遞的參數是 Promise 類型的對象,則返回的結果由返回的 Promise 決定,如果返回的是 resolve 則是成功的狀態,進入下一個 then 里,如果返回的是 reject 則是失敗的狀態,進入下一個 catch 里

reject

  1. 如果傳遞的參數是非 Promise 類型的對象,則返回的結果是拒絕狀態的 Promise 對象,進入下一個 catch 里面或者是下一個 then 的第二個參數 reject 回調里面

  2. 如果傳遞的參數是 Promise 類型的對象,則返回的結果由返回的 Promise 決定,如果返回的是 resolve 則是成功的狀態,進入下一個 then 里,如果返回的是 reject 則是拒絕的狀態,進入下一個 catch 里面或者是下一個 then 的第二個參數 reject 回調里面

這在我們自己封裝的 API 里面也有體現:為什么 code 為 1 時都是 then 接收,其他都是 catch 接收,就是因為在 then 里面也就是 resolve 函數中對 code 碼進行了判斷,如果是 1 則返回 Promise.resolve (),進入 then 里處理,如果是非 1 則返回 Promise.reject (),進入 catch 里處理。

流程圖

a064244a-9296-11ee-939d-92fbcf53809c.png?簡單使用
// 模擬一個promise的get請求
let count = 0
function customGet(url){
    count += 1
    return new Promise((resolve, reject)=>{
        const xmlHttp = new XMLHttpRequest();
        xmlHttp.open("GET",url, true);
        xmlHttp.onload = ()=>{
          console.log(xmlHttp, 'xmlHttp---onload');
          if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
            console.log('customGet請求成功了');
            // 返回非Promise,結果為成功狀態
            resolve({data:`第${count}次請求獲取數據成功`})

            // 返回Promise,結果由Promise決定
            // resolve(Promise.reject('resolve中返回reject'))
          } else {
            reject('customGet請求錯誤了')
          }
        }

        // Promise狀態改變就不會再變
        // onreadystatechange方法會被執行四次
        // 當地次進來的時候,readyState不等于4,執行else邏輯,執行reject,狀態變為Rejected,所以即使再執行if,狀態之后不會再改變
        // xmlHttp.onreadystatechange = function(){
        //   console.log(xmlHttp,'xmlHttp---onreadystatechange')
        //   if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        //     console.log('customGet請求成功了');
        //     resolve({data:`第${count}次請求獲取數據成功`})
        //   } else {
        //     reject('customGet請求錯誤了')
        //   }
        // }
        xmlHttp.send();
      })
 }

// 使用Promise,并且進行鏈式調用
customGet('https://v0.yiketianqi.com/api/cityall?appid=&appsecret=').then((res)=>{
   console.log(res.data);
   return '第一次請求處理后的數據'
}).then((data)=>{
   console.log(data)
   // console.log(data.toFixed());
   return customGet('https://v0.yiketianqi.com/api/cityall?appid=&appsecret=')
}).then((res)=>{
   console.log(res.data);
}).catch((err)=>{
    // 以類似'冒泡'的性質再外層捕獲所有的錯誤
   console.error(err, '這是catch里的錯誤信息');
})

手寫實現簡單的 Promise通過上面的回顧,我們已經了解了 Promise 的關鍵屬性和特點,下面我們一起來實現一個簡單的 Promise 吧
  // 1、封裝一個Promise構造函數,有一個函數參數
  function Promise(executor){
    // 7、添加對象屬性PromiseState PromiseResult
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 14、創建一個保存成功失敗回調函數的屬性
    this.callback = null

    // 8、this指向問題
    const that = this

    // 4、executor有兩個函數參數(resolve,reject)
    function resolve(data){
      // 10、Promise狀態只能修改一次(同時記得處理reject中的狀態)
      if(that.PromiseState !== 'pending') return

      // console.log(this, 'this');
      // 5、修改對象的狀態PromiseState
      that.PromiseState = 'Fulfilled'

      // 6、修改對象的結果PromiseResult
      that.PromiseResult = data

      // 15、異步執行then里的回調函數
      if(that.callback?.onResolve){
        that.callback.onResolve(that.PromiseResult)
      }
    }
    function reject(data){
      console.log(that.PromiseState, 'that.PromiseState');
      if(that.PromiseState !== 'pending') return

      // 9、處理失敗函數狀態
      that.PromiseState = 'Rejected'
      that.PromiseResult = data
      console.log(that.PromiseResult, 'that.PromiseResult');
      console.log(that.PromiseState, 'that.PromiseState');

      // 16、異步執行then里的回調函數
      if(that.callback?.onReject){
        that.callback.onReject(that.PromiseResult)
      }
    }
    // 3、執行器函數是同步調用的,并且有兩個函數參數
    executor(resolve,reject)
  }
  // 2、函數的實例上有方法then
  Promise.prototype.then = function(onResolve,onReject){
    // 20、處理onReject沒有的情況
    if(typeof onReject !== 'function'){
      onReject = reason => {
        throw reason
      }
    }
    // 21、處理onResolve沒有的情況
    if(typeof onResolve !== 'function'){
      onResolve = value => value
    }
    // 17、每一個then方法都返回一個新的Promise,并且把上一個then返回的結果傳遞出去
    return new Promise((nextResolve,nextReject)=>{
      // 11、處理成功或失敗
      if(this.PromiseState === 'Fulfilled'){
        // 12、將結果傳遞給函數
        // onResolve(this.PromiseResult)

        // 18、拿到上一次執行完后返回的結果,判斷是不是Promise
        const result = onResolve(this.PromiseResult)
        if(result instanceof Promise){
          result.then((v)=>{
            nextResolve(v)
          },(r)=>{
            nextReject(r)
          })
        } else {
          nextResolve(result)
        }
      }
      // 當你一步步寫下來的時候有沒有懷疑過為什么不用else
       if(this.PromiseState === 'Rejected'){
            // 第12步同時處理此邏輯
            // onReject(this.PromiseResult)

            // 22、處理catch異常穿透捕獲錯誤
            try {
              const result = onReject(this.PromiseResult)
              if(result instanceof Promise){
                result.then((v)=>{
                  nextResolve(v)
                }).catch((r)=>{
                  nextReject(r)
                })
              } else {
                nextReject(result)
              }
            } catch (error) {
              nextReject(this.PromiseResult)
            }
         }
  
      // 13、異步任務時處理成功或失敗,想辦法等異步任務執行完成后才去執行這兩個函數
      if(this.PromiseState === 'pending'){
        this.callback = {
          onResolve,
          onReject
        }
        console.log(this.callback, 'this.callback');
      }
    })
  }
  // 19、函數實例上有方法catch
  Promise.prototype.catch = function(onReject) {
    return this.then(null,onReject)
  }

  // 使用自定義封裝的Promise
  const customP = new Promise((resolve,reject)=>{
    // 模擬異步執行請求
    // const xmlHttp = new XMLHttpRequest();
    // xmlHttp.open("GET",'https://v0.yiketianqi.com/api/cityall?appid=&appsecret=', true);
    // xmlHttp.onload = ()=>{
    //   if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
    //     resolve('success')
    //   } else {
    //     reject('error')
    //   }
    // }
    // xmlHttp.send();

    // 同步執行
    resolve('success')
    // reject('error')
  })

  console.log(customP, 'customP');
  customP.then((res)=>{
    console.log(res, 'resolve回調');
    return '第一次回調'
    // return new Promise((resolve,reject)=>{
    //   reject('錯錯錯')
    // })
  },(err)=>{
    console.error(err, 'reject回調');
    return '2121'
  }).then(()=>{
    console.log('then里面輸出');
  }).then().catch((err)=>{
    console.error(err, 'catch里的錯誤');
  })

針對 resolve 中返回 Promise 對象時的內部執行順序a076ff7a-9296-11ee-939d-92fbcf53809c.png??總結以上就是我們常用的 Promise 基礎實現,在實現過程中對比了 Promise 和函數嵌套處理異步請求的優缺點,Promise 仍存在缺點,但是的確方便很多,同時更清晰的理解到錯誤處理如何進行異常穿透的,也能幫助我們更規范的使用 Promise 以及快速定位問題所在。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 耦合
    +關注

    關注

    13

    文章

    583

    瀏覽量

    100905
  • 代碼
    +關注

    關注

    30

    文章

    4801

    瀏覽量

    68735
  • 執行器
    +關注

    關注

    5

    文章

    378

    瀏覽量

    19373

原文標題:Promise規范與原理解析

文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    鴻蒙原生應用開發-ArkTS語言基礎類庫異步并發簡述Promise

    Promise和async/await提供異步并發能力,是標準的JS異步語法。異步代碼會被掛起并在之后繼續執行,同一時間只有一段代碼執行,適用于單次I/O任務的場景開發,例如一次網絡請求、一次文件
    發表于 03-07 15:46

    手機通信原理解析

    `手機通信原理解析:第 1 章    無線通信原理第2 章    移動通信系統第3 章    移動通信系統的多址接入技術第4 章    移動通信系統的語音編碼第5 章 GSM移動通信系統的數字
    發表于 12-14 14:31

    定位技術原理解析

    【追蹤嫌犯的利器】定位技術原理解析(4)
    發表于 05-04 12:20

    Promise對象的基礎知識

    Promise 對象學習筆記
    發表于 06-04 16:19

    如何使用abortController終止fetch和promise

    使用abortController 終止fetch和promise的方法
    發表于 11-05 08:07

    鋰電池基本原理解析

    【鋰知道】鋰電池基本原理解析:充電及放電機制電池充電最重要的就是這三步:第一步:判斷電壓
    發表于 09-15 06:47

    如何更好地理解各種抖動技術規范

    今天,我將幫助您了解如何更好地理解各種抖動技術規范。隨著高速應用中的定時要求日趨嚴格,對各種抖動技術規范的更深入理解現已變得非常重要。從 10Gb 以太網網絡到 PCIe 等高速互聯技
    發表于 11-21 06:02

    虛擬存儲器部件原理解析

    虛擬存儲器部件原理解析
    發表于 04-15 14:25 ?3136次閱讀

    觸摸屏的應用與工作原理解析

    觸摸屏的應用與工作原理解析
    發表于 02-08 02:13 ?38次下載

    如何更好的理解抖動技術規范

    歡迎繼續關注《定時決定一切》系列文章!上次我們探討了對 PLL 環路濾波器響應的理解。今天,我將幫助您了解如何更好地理解各種抖動技術規范。隨著高速應用中的定時要求日趨嚴格,對各種抖動技術規范
    發表于 04-08 04:56 ?965次閱讀
    如何更好的<b class='flag-5'>理解</b>抖動技術<b class='flag-5'>規范</b>?

    關于Nodejs中最關鍵也是最難的異步編程做一些介紹和講解

    人們對于新事物的快速理解一般基于此新事物與生活中某種事物或者規律的的相似性,但這個promise并沒有這種特點,在我看來,可以去類比promise這個概念的東西相當少,而且類比得相當勉強,但這也并不意味著
    的頭像 發表于 04-13 10:17 ?6461次閱讀
    關于Nodejs中最關鍵也是最難的異步編程做一些介紹和講解

    CF210SP型調頻調幅收音機電路圖及原理解析

    CF210SP型調頻調幅收音機電路圖及原理解析
    發表于 01-25 10:46 ?123次下載

    史密斯圓圖和阻抗匹配原理解析

    史密斯圓圖和阻抗匹配原理解析
    的頭像 發表于 11-02 20:16 ?2019次閱讀

    什么是晶振 晶振工作原理解析

    什么是晶振 晶振工作原理解析
    的頭像 發表于 12-30 17:13 ?4363次閱讀
    什么是晶振 晶振工作原<b class='flag-5'>理解析</b>

    電磁屏蔽技術的原理解析

    電磁屏蔽技術的原理解析 電磁屏蔽技術是一種利用特定材料或構造來阻擋、吸收或反射外界電磁波的技術。它在電子設備、通信系統以及電磁環境的凈化等方面具有重要應用,可以有效地防止電磁干擾,保護設備和人員
    的頭像 發表于 03-06 14:58 ?2775次閱讀
    主站蜘蛛池模板: 国产午夜精品久久久久婷婷| 国产成人高清精品免费观看| 插我一区二区在线观看| 精品国产乱码久久久久久下载| 色综合久久五月| 成人手机在线| 欧美最猛黑人AAAAA片| black大战chinese周晓琳| 男宿舍里的呻吟h| 99热精品在线视频观看| 女人操男人| 潮 喷女王cytherea| 色妺妺免费影院| 国产精品第1页在线观看| 偷偷鲁青春草原视频| 狼人大香伊蕉国产WWW亚洲| 亚洲欧洲久久| 精品国产在线观看福利| 在线视频 国产精品 中文字幕 | 一区二区三区内射美女毛片| 久久精品国产只有精品| 中文字幕在线观看亚洲视频| 嫩草影院久久精品| 处破女免费播放| 亚洲国产高清在线观看视频| 九九视频在线观看视频6| 2019在秋霞理论| 秋霞电影在线观看午夜伦| 国产成人综合高清在线观看| 亚洲AV噜噜88| 久久综合亚洲色hezyo| ppypp午夜限制不卡影院私人| 三级黃60分钟| 精品国产成人AV在线看| 18美女腿打开无遮软件| 日本最新在线不卡免费视频| 国产精品视频大全| 亚洲人精品午夜射精日韩| 看 视频一一级毛片| 被男按摩师添的好爽在线直播| 小sao货水好多真紧h的视频|