一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

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

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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

OSC開源社區(qū) ? 來(lái)源:OSC開源社區(qū) ? 2023-12-05 15:49 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

摘要

Promise 對(duì)象用于清晰的處理異步任務(wù)的完成,返回最終的結(jié)果值,本次分享主要介紹 Promise 的基本屬性以及 Promise 內(nèi)部的基礎(chǔ)實(shí)現(xiàn),能夠幫我們更明確使用場(chǎng)景、更快速定位問(wèn)題。

Promise 出現(xiàn)的原因

首先我們先來(lái)看一段代碼:異步請(qǐng)求的層層嵌套
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');
      // 請(qǐng)求2
      (function fn2() {
        xmlHttp.onreadystatechange = function(){
        if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
          const fn2Data = {name: `${fn1Data.name}-fn2`}
          console.log(fn2Data, 'fn2Data');
          // 請(qǐng)求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,我在函數(shù)${params}中執(zhí)行?。。);
}
  
function fn2(params) {
  try {
    const xmlHttp = new XMLHttpRequest();
    xmlHttp.onreadystatechange = function(){
      if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        console.log(`我是fn2,我在函數(shù)${params}中執(zhí)行?。?!結(jié)果是:`,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請(qǐng)求已完成');
          fn2('fn3')
      }
    }
    xmlHttp.open("GET","https://v0.yiketianqi.com/api?unescape=1&version=v61", true);
    xmlHttp.send();
    console.log('我是f3函數(shù)呀');
  } catch (error) {
    console.error(error);
  }
}
  
fn3()

由上面的兩種寫法的請(qǐng)求可見,在 promise 之前,為了進(jìn)行多個(gè)異步請(qǐng)求并且依賴上一個(gè)異步請(qǐng)求的結(jié)果時(shí),我們必須進(jìn)行層層嵌套,大多數(shù)情況下,我們又對(duì)異步結(jié)果進(jìn)行數(shù)據(jù)處理,這樣使得我們的代碼非常難看,并且難以維護(hù),這就形成了回調(diào)地獄,由此 Promise 開始出現(xiàn)了。回調(diào)地獄缺點(diǎn)
  • 代碼臃腫

  • 可讀性差

  • 耦合性高

  • 不好進(jìn)行異常處理

Promise 的基本概念

含義

  1. ES6 將其寫進(jìn)了語(yǔ)言標(biāo)準(zhǔn)里統(tǒng)一了用法,是一個(gè)構(gòu)造函數(shù),用來(lái)生成 Promise 實(shí)例

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

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

  4. then、catch、finally 方法為 Promise 實(shí)例上的方法

狀態(tài)

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

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

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

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

  5. 有兩個(gè)關(guān)鍵的屬性:PromiseState --- 狀態(tài)改變,PromiseResult --- 結(jié)果數(shù)據(jù)改變

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

// 狀態(tài)改變PromiseState 結(jié)果改變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='我錯(cuò)了'
console.log(p3, 'p3'); // then為實(shí)例上的方法,報(bào)錯(cuò)
console.log(p4, 'p4');  // catch為實(shí)例上的方法,報(bào)錯(cuò)
a047ff72-9296-11ee-939d-92fbcf53809c.png?特點(diǎn)1.錯(cuò)誤信息清晰定位:可以在外層捕獲異常信息(網(wǎng)絡(luò)錯(cuò)誤、語(yǔ)法錯(cuò)誤都可以捕獲),有 “冒泡” 性質(zhì),會(huì)一直向后傳遞,直到被捕獲,所以在最后寫一個(gè) catch 就可以了2.鏈?zhǔn)秸{(diào)用:每一個(gè) then 和 catch 都會(huì)返回一個(gè)新的 Promise,把結(jié)果傳遞到下一個(gè) then/catch 中,因此可以進(jìn)行鏈?zhǔn)秸{(diào)用 --- 代碼簡(jiǎn)潔清晰

結(jié)果由什么決定

resolve

  1. 如果傳遞的參數(shù)是非 Promise 類型的對(duì)象,則返回的結(jié)果是成功狀態(tài)的 Promise 對(duì)象,進(jìn)入下一個(gè) then 里面

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

reject

  1. 如果傳遞的參數(shù)是非 Promise 類型的對(duì)象,則返回的結(jié)果是拒絕狀態(tài)的 Promise 對(duì)象,進(jìn)入下一個(gè) catch 里面或者是下一個(gè) then 的第二個(gè)參數(shù) reject 回調(diào)里面

  2. 如果傳遞的參數(shù)是 Promise 類型的對(duì)象,則返回的結(jié)果由返回的 Promise 決定,如果返回的是 resolve 則是成功的狀態(tài),進(jìn)入下一個(gè) then 里,如果返回的是 reject 則是拒絕的狀態(tài),進(jìn)入下一個(gè) catch 里面或者是下一個(gè) then 的第二個(gè)參數(shù) reject 回調(diào)里面

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

流程圖

a064244a-9296-11ee-939d-92fbcf53809c.png?簡(jiǎn)單使用
// 模擬一個(gè)promise的get請(qǐng)求
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請(qǐng)求成功了');
            // 返回非Promise,結(jié)果為成功狀態(tài)
            resolve({data:`第${count}次請(qǐng)求獲取數(shù)據(jù)成功`})

            // 返回Promise,結(jié)果由Promise決定
            // resolve(Promise.reject('resolve中返回reject'))
          } else {
            reject('customGet請(qǐng)求錯(cuò)誤了')
          }
        }

        // Promise狀態(tài)改變就不會(huì)再變
        // onreadystatechange方法會(huì)被執(zhí)行四次
        // 當(dāng)?shù)卮芜M(jìn)來(lái)的時(shí)候,readyState不等于4,執(zhí)行else邏輯,執(zhí)行reject,狀態(tài)變?yōu)镽ejected,所以即使再執(zhí)行if,狀態(tài)之后不會(huì)再改變
        // xmlHttp.onreadystatechange = function(){
        //   console.log(xmlHttp,'xmlHttp---onreadystatechange')
        //   if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
        //     console.log('customGet請(qǐng)求成功了');
        //     resolve({data:`第${count}次請(qǐng)求獲取數(shù)據(jù)成功`})
        //   } else {
        //     reject('customGet請(qǐng)求錯(cuò)誤了')
        //   }
        // }
        xmlHttp.send();
      })
 }

// 使用Promise,并且進(jìn)行鏈?zhǔn)秸{(diào)用
customGet('https://v0.yiketianqi.com/api/cityall?appid=&appsecret=').then((res)=>{
   console.log(res.data);
   return '第一次請(qǐng)求處理后的數(shù)據(jù)'
}).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)=>{
    // 以類似'冒泡'的性質(zhì)再外層捕獲所有的錯(cuò)誤
   console.error(err, '這是catch里的錯(cuò)誤信息');
})

手寫實(shí)現(xiàn)簡(jiǎn)單的 Promise通過(guò)上面的回顧,我們已經(jīng)了解了 Promise 的關(guān)鍵屬性和特點(diǎn),下面我們一起來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的 Promise 吧
  // 1、封裝一個(gè)Promise構(gòu)造函數(shù),有一個(gè)函數(shù)參數(shù)
  function Promise(executor){
    // 7、添加對(duì)象屬性PromiseState PromiseResult
    this.PromiseState = 'pending'
    this.PromiseResult = null

    // 14、創(chuàng)建一個(gè)保存成功失敗回調(diào)函數(shù)的屬性
    this.callback = null

    // 8、this指向問(wèn)題
    const that = this

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

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

      // 6、修改對(duì)象的結(jié)果PromiseResult
      that.PromiseResult = data

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

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

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

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

            // 22、處理catch異常穿透捕獲錯(cuò)誤
            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、異步任務(wù)時(shí)處理成功或失敗,想辦法等異步任務(wù)執(zhí)行完成后才去執(zhí)行這兩個(gè)函數(shù)
      if(this.PromiseState === 'pending'){
        this.callback = {
          onResolve,
          onReject
        }
        console.log(this.callback, 'this.callback');
      }
    })
  }
  // 19、函數(shù)實(shí)例上有方法catch
  Promise.prototype.catch = function(onReject) {
    return this.then(null,onReject)
  }

  // 使用自定義封裝的Promise
  const customP = new Promise((resolve,reject)=>{
    // 模擬異步執(zhí)行請(qǐng)求
    // 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回調(diào)');
    return '第一次回調(diào)'
    // return new Promise((resolve,reject)=>{
    //   reject('錯(cuò)錯(cuò)錯(cuò)')
    // })
  },(err)=>{
    console.error(err, 'reject回調(diào)');
    return '2121'
  }).then(()=>{
    console.log('then里面輸出');
  }).then().catch((err)=>{
    console.error(err, 'catch里的錯(cuò)誤');
  })

針對(duì) resolve 中返回 Promise 對(duì)象時(shí)的內(nèi)部執(zhí)行順序a076ff7a-9296-11ee-939d-92fbcf53809c.png??總結(jié)以上就是我們常用的 Promise 基礎(chǔ)實(shí)現(xiàn),在實(shí)現(xiàn)過(guò)程中對(duì)比了 Promise 和函數(shù)嵌套處理異步請(qǐng)求的優(yōu)缺點(diǎn),Promise 仍存在缺點(diǎn),但是的確方便很多,同時(shí)更清晰的理解到錯(cuò)誤處理如何進(jìn)行異常穿透的,也能幫助我們更規(guī)范的使用 Promise 以及快速定位問(wèn)題所在。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 耦合
    +關(guān)注

    關(guān)注

    13

    文章

    596

    瀏覽量

    101670
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4900

    瀏覽量

    70758
  • 執(zhí)行器
    +關(guān)注

    關(guān)注

    5

    文章

    387

    瀏覽量

    19918

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

文章出處:【微信號(hào):OSC開源社區(qū),微信公眾號(hào):OSC開源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    鴻蒙原生應(yīng)用開發(fā)-ArkTS語(yǔ)言基礎(chǔ)類庫(kù)異步并發(fā)簡(jiǎn)述Promise

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

    手機(jī)通信原理解析

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

    定位技術(shù)原理解析

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

    Promise對(duì)象的基礎(chǔ)知識(shí)

    Promise 對(duì)象學(xué)習(xí)筆記
    發(fā)表于 06-04 16:19

    如何使用abortController終止fetch和promise?

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

    鋰電池基本原理解析

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

    如何更好地理解各種抖動(dòng)技術(shù)規(guī)范

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

    虛擬存儲(chǔ)器部件原理解析

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

    觸摸屏的應(yīng)用與工作原理解析

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

    如何更好的理解抖動(dòng)技術(shù)規(guī)范?

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

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

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

    CF210SP型調(diào)頻調(diào)幅收音機(jī)電路圖及原理解析

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

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

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

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

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

    電磁屏蔽技術(shù)的原理解析

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