女人自慰AV免费观看内涵网,日韩国产剧情在线观看网址,神马电影网特片网,最新一级电影欧美,在线观看亚洲欧美日韩,黄色视频在线播放免费观看,ABO涨奶期羡澄,第一导航fulione,美女主播操b

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

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

3天內不再提示

Promise規(guī)范與原理解析

OSC開源社區(qū) ? 來源:OSC開源社區(qū) ? 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()

或者我們可以將上面的代碼優(yōu)化為下面這樣

function fn1(params) {
  console.log(`我是fn1,我在函數${params}中執(zhí)行!!!`);
}
  
function fn2(params) {
  try {
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function(){
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        console.log(`我是fn2,我在函數${params}中執(zhí)行!!!結果是:`,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 將其寫進了語言標準里統(tǒng)一了用法,是一個構造函數,用來生成 Promise 實例

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

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

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

狀態(tài)

  1. pending --- 等待狀態(tài)

  2. Fulfilled --- 執(zhí)行狀態(tài) (resolve 回調函數,then)

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

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

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

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

// 狀態(tài)改變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 類型的對象,則返回的結果是成功狀態(tài)的 Promise 對象,進入下一個 then 里面

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

reject

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

  2. 如果傳遞的參數是 Promise 類型的對象,則返回的結果由返回的 Promise 決定,如果返回的是 resolve 則是成功的狀態(tài),進入下一個 then 里,如果返回的是 reject 則是拒絕的狀態(tài),進入下一個 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,結果為成功狀態(tài)
            resolve({data:`第${count}次請求獲取數據成功`})

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

        // Promise狀態(tài)改變就不會再變
        // onreadystatechange方法會被執(zhí)行四次
        // 當地次進來的時候,readyState不等于4,執(zhí)行else邏輯,執(zhí)行reject,狀態(tài)變?yōu)镽ejected,所以即使再執(zhí)行if,狀態(tài)之后不會再改變
        // 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、創(chuàng)建一個保存成功失敗回調函數的屬性
    this.callback = null

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

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

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

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

      // 15、異步執(zhí)行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、處理失敗函數狀態(tài)
      that.PromiseState = 'Rejected'
      that.PromiseResult = data
      console.log(that.PromiseResult, 'that.PromiseResult');
      console.log(that.PromiseState, 'that.PromiseState');

      // 16、異步執(zhí)行then里的回調函數
      if(that.callback?.onReject){
        that.callback.onReject(that.PromiseResult)
      }
    }
    // 3、執(zhí)行器函數是同步調用的,并且有兩個函數參數
    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、拿到上一次執(zhí)行完后返回的結果,判斷是不是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、異步任務時處理成功或失敗,想辦法等異步任務執(zhí)行完成后才去執(zhí)行這兩個函數
      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)=>{
    // 模擬異步執(zhí)行請求
    // 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();

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

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

    關注

    13

    文章

    595

    瀏覽量

    101483
  • 代碼
    +關注

    關注

    30

    文章

    4886

    瀏覽量

    70248
  • 執(zhí)行器
    +關注

    關注

    5

    文章

    382

    瀏覽量

    19761

原文標題:Promise規(guī)范與原理解析

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

收藏 人收藏

    評論

    相關推薦
    熱點推薦

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

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

    手機通信原理解析

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

    定位技術原理解析

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

    Promise對象的基礎知識

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

    如何使用abortController終止fetch和promise

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

    鋰電池基本原理解析

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

    如何更好地理解各種抖動技術規(guī)范

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

    虛擬存儲器部件原理解析

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

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

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

    如何更好的理解抖動技術規(guī)范

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

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

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

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

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

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

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

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

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

    電磁屏蔽技術的原理解析

    電磁屏蔽技術的原理解析 電磁屏蔽技術是一種利用特定材料或構造來阻擋、吸收或反射外界電磁波的技術。它在電子設備、通信系統(tǒng)以及電磁環(huán)境的凈化等方面具有重要應用,可以有效地防止電磁干擾,保護設備和人員
    的頭像 發(fā)表于 03-06 14:58 ?4618次閱讀