主頁 > 企業開發 > 講講 Promise

講講 Promise

2020-09-15 15:30:14 企業開發

一、什么是 Promise

1.1 Promise 的前世今生

Promise 最早出現在 1988 年,由 Barbara Liskov、Liuba Shrira 首創(論文:Promises: Linguistic Support for Efficient Asynchronous Procedure Calls in Distributed Systems),并且在語言 MultiLisp 和 Concurrent Prolog 中已經有了類似的實作,

JavaScript 中,Promise 的流行是得益于 jQuery 的方法 jQuery.Deferred(),其他也有一些更精簡獨立的 Promise 庫,例如:Q、When、Bluebird,

# Q / 2010
import Q from 'q'

function wantOdd () {
    const defer = Q.defer()
    const num = Math.floor(Math.random() * 10)
    if (num % 2) {
        defer.resolve(num)
    } else {
        defer.reject(num)
    }
    return defer.promise
}

wantOdd()
    .then(num => {
        log(`Success: ${num} is odd.`) // Success: 7 is odd.
    })
    .catch(num => {
        log(`Fail: ${num} is not odd.`)
    })

由于 jQuery 并沒有嚴格按照規范來制定介面,促使了官方對 Promise 的實作標準進行了一系列重要的澄清,該實作規范被命名為 Promise/A+,后來 ES6(也叫 ES2015,2015 年 6 月正式發布)也在 Promise/A+ 的標準上官方實作了一個 Promise 介面,

new Promise( function(resolve, reject) {...} /* 執行器 */  );

想要實作一個 Promise,必須要遵循如下規則:

  1. Promise 是一個提供符合標準的 then() 方法的物件,
  2. 初始狀態是 pending,能夠轉換成 fulfilledrejected 狀態,
  3. 一旦 fulfilledrejected 狀態確定,再也不能轉換成其他狀態,
  4. 一旦狀態確定,必須要回傳一個值,并且這個值是不可修改的,

狀態

ECMAScript's Promise global is just one of many Promises/A+ implementations.

主流語言對于 Promise 的實作:Golang/go-promise、Python/promise、C#/Real-Serious-Games/c-sharp-promise、PHP/Guzzle Promises、Java/IOU、Objective-C/PromiseKit、Swift/FutureLib、Perl/stevan/promises-perl,

旨在解決的問題

由于 JavaScript 是單執行緒事件驅動的編程語言,通過回呼函式管理多個任務,在快速迭代的開發中,因為回呼函式的濫用,很容易產生被人所詬病的回呼地獄問題,Promise 的異步編程解決方案比回呼函式更加合理,可讀性更強,

傳說中比較夸張的回呼:

回呼地獄

現實業務中依賴關系比較強的回呼:

# 回呼函式
function renderPage () {
    const secret = genSecret()
    // 獲取用戶令牌
    getUserToken({
        secret,
        success: token => {
            // 獲取游戲串列
            getGameList({
                token,
                success: data =https://www.cnblogs.com/mazey/p/> {
                    // 渲染游戲串列
                    render({
                        list: data.list,
                        success: () => {
                            // 埋點資料上報
                            report()
                        },
                        fail: err => {
                            console.error(err)
                        }
                    })
                },
                fail: err => {
                    console.error(err)
                }
            })
        },
        fail: err => {
            console.error(err)
        }
    })
}

使用 Promise 梳理流程后:

# Promise
function renderPage () {
    const secret = genSecret()
    // 獲取用戶令牌
    getUserToken(token)
        .then(token => {
            // 獲取游戲串列
            return getGameList(token)
        })
        .then(data =https://www.cnblogs.com/mazey/p/> {
            // 渲染游戲串列
            return render(data.list) 
        })
        .then(() => {
            // 埋點資料上報
            report()
        })
        .catch(err => {
            console.error(err)
        })
}

1.2 實作一個超簡易版的 Promise

Promise 的運轉實際上是一個觀察者模式,then() 中的匿名函式充當觀察者,Promise 實體充當被觀察者,

const p = new Promise(resolve => setTimeout(resolve.bind(null, 'from promise'), 3000))

p.then(console.log.bind(null, 1))
p.then(console.log.bind(null, 2))
p.then(console.log.bind(null, 3))
p.then(console.log.bind(null, 4))
p.then(console.log.bind(null, 5))
// 3 秒后
// 1 2 3 4 5 from promise

觀察者模式

# 實作
const defer = () => {
    let pending = [] // 充當狀態并收集觀察者
    let value = https://www.cnblogs.com/mazey/p/undefined
    return {
        resolve: (_value) => { // FulFilled!
            value = _value
            if (pending) {
                pending.forEach(callback => callback(value))
                pending = undefined
            }
        },
        then: (callback) => {
            if (pending) {
                pending.push(callback)
            } else {
                callback(value)
            }
        }
    }
}

# 模擬
const mockPromise = () => {
    let p = defer()
    setTimeout(() => {
        p.resolve('success!')
    }, 3000)
    return p
}

mockPromise().then(res => {
    console.log(res)
})

console.log('script end')
// script end
// 3 秒后
// success!

二、Promise 怎么用

2.1 使用 Promise 異步編程

Promise 出現之前往往使用回呼函式管理一些異步程式的狀態,

回呼函式

# 常見的異步 Ajax 請求格式
ajax(url, successCallback, errorCallback)

Promise 出現后使用 then() 接收事件的狀態,且只會接收一次,

案例:插件初始化,

使用回呼函式:

# 插件代碼
let ppInitStatus = false
let ppInitCallback = null
PP.init = callback => {
    if (ppInitStatus) {
        callback && callback(/* 資料 */)
    } else {
        ppInitCallback = callback
    }
}
// ...
// ...
// 經歷了一系列同步異步程式后初始化完成
ppInitCallback && ppInitCallback(/* 資料 */)
ppInitStatus = true

# 第三方呼叫
PP.init(callback)

使用 Promise:

# 插件代碼
let initOk = null
const ppInitStatus = new Promise(resolve => initOk = resolve)
PP.init = callback => {
    ppInitStatus.then(callback).catch(console.error)
}
// ...
// ...
// 經歷了一系列同步異步程式后初始化完成
initOk(/* 資料 */)

# 第三方呼叫
PP.init(callback)

相對于使用回呼函式,邏輯更清晰,什么時候初始化完成和觸發回呼一目了然,不再需要重復判斷狀態和回呼函式,當然更好的做法是只給第三方輸出狀態資料,至于如何使用由第三方決定,

# 插件代碼
let initOk = null
PP.init = new Promise(resolve => initOk = resolve)
// ...
// ...
// 經歷了一系列同步異步程式后初始化完成
initOk(/* 資料 */)

# 第三方呼叫
PP.init.then(callback).catch(console.error)

2.2 鏈式呼叫

then() 必然回傳一個 Promise 物件,Promise 物件又擁有一個 then() 方法,這正是 Promise 能夠鏈式呼叫的原因,

const p = new Promise(r => r(1))
    .then(res => {
        console.log(res) // 1
        return Promise.resolve(2)
        .then(res => res + 10) // === new Promise(r => r(1))
        .then(res => res + 10) // 由此可見,每次回傳的是實體后面跟的最后一個 then
    })
    .then(res => {
        console.log(res) // 22
        return 3 // === Promise.resolve(3)
    })
    .then(res => {
        console.log(res) // 3
    })
    .then(res => {
        console.log(res) // undefined
        return '最強王者'
    })

p.then(console.log.bind(null, '是誰活到了最后:')) // 是誰活到了最后: 最強王者

由于回傳一個 Promise 結構體永遠回傳的是鏈式呼叫的最后一個 then(),所以在處理封裝好的 Promise 介面時沒必要在外面再包一層 Promise

# 包一層 Promise
function api () {
    return new Promise((resolve, reject) => {
        axios.get(/* 鏈接 */).then(data =https://www.cnblogs.com/mazey/p/> {
            // ...
            // 經歷了一系列資料處理
            resolve(data.xxx)
        })
    })
}

# 更好的做法:利用鏈式呼叫
function api () {
    return axios.get(/* 鏈接 */).then(data => {
        // ...
        // 經歷了一系列資料處理
        return data.xxx
    })
}

2.3 管理多個 Promise 實體

Promise.all() / Promise.race() 可以將多個 Promise 實體包裝成一個 Promise 實體,在處理并行的、沒有依賴關系的請求時,能夠節約大量的時間,

function wait (ms) {
    return new Promise(resolve => setTimeout(resolve.bind(null, ms), ms))
}

# Promise.all
Promise.all([wait(2000), wait(4000), wait(3000)])
    .then(console.log)
// 4 秒后 [ 2000, 4000, 3000 ]

# Promise.race
Promise.race([wait(2000), wait(4000), wait(3000)])
    .then(console.log)
// 2 秒后 2000

2.4 Promiseasync / await

async / await 實際上只是建立在 Promise 之上的語法糖,讓異步代碼看上去更像同步代碼,所以 async / await 在 JavaScript 執行緒中是非阻塞的,但在當前函式作用域內具備阻塞性質,

let ok = null
async function foo () {
    console.log(1)
    console.log(await new Promise(resolve => ok = resolve))
    console.log(3)
}
foo() // 1
ok(2) // 2 3

使用 async / await 的優勢:

  1. 簡潔干凈

    寫更少的代碼,不需要特地創建一個匿名函式,放入 then() 方法中等待一個回應,

    # Promise
    function getUserInfo () {
        return getData().then(
            data =https://www.cnblogs.com/mazey/p/> {
                return data
            }
        )
    }
    
    # async / await
    async function getUserInfo () {
        return await getData()
    }
    
  2. 條件陳述句

    當一個異步回傳值是另一段邏輯的判斷條件,鏈式呼叫將隨著層級的疊加變得更加復雜,讓人很容易在代碼中迷失自我,使用 async / await 將使代碼可讀性變得更好,

    # Promise
    function getGameInfo () {
        getUserAbValue().then(
            abValue =https://www.cnblogs.com/mazey/p/> {
                if (abValue === 1) {
                    return getAInfo().then(
                        data => {
                            // ...
                        }
                    )
                } else {
                    return getBInfo().then(
                        data => {
                            // ...
                        }
                    )
                }
            }
        )
    }
    
    # async / await
    async function getGameInfo () {
        const abValue = await getUserAbValue()
        if (abValue === 1) {
            const data = await getAInfo()
            // ...
        } else {
            // ...
        }
    }
    
  3. 中間值

    異步函式常常存在一些異步回傳值,作用僅限于成為下一段邏輯的入場券,如果經歷層層鏈式呼叫,很容易成為另一種形式的“回呼地獄”,

    # Promise
    function getGameInfo () {
        getToken().then(
            token => {
                getLevel(token).then(
                    level => {
                        getInfo(token, level).then(
                            data =https://www.cnblogs.com/mazey/p/> {
                                // ...
                            }
                        )
                    }
                )
            }
        )
    }
    
    # async / await
    async function getGameInfo() {
        const token = await getToken()
        const level = await getLevel(token)
        const data = await getInfo(token, level)
        // ...
    }
    
  4. 靠譜的 await

    await 'qtt' 等于 await Promise.resolve('qtt')await 會把任何不是 Promise 的值包裝成 Promise,看起來貌似沒有什么用,但是在處理第三方介面的時候可以 “Hold” 住同步和異步回傳值,否則對一個非 Promise 回傳值使用 then() 鏈式呼叫則會報錯,

使用 async / await 的缺點:

  1. async 永遠回傳 Promise 物件,不夠靈活,很多時候我只想單純回傳一個基本型別值,

  2. await 阻塞 async 函式中的代碼執行,在背景關系關聯性不強的代碼中略顯累贅,

    # async / await
    async function initGame () {
        render(await getGame()) // 等待獲取游戲執行完畢再去獲取用戶資訊
        report(await getUserInfo())
    }
    
    # Promise
    function initGame () {
        getGame()
            .then(render)
            .catch(console.error)
        getUserInfo() // 獲取用戶資訊和獲取游戲同步進行
            .then(report)
            .catch(console.error)
    }
    

2.5 錯誤處理

  1. 鏈式呼叫中盡量結尾跟 catch 捕獲錯誤,而不是第二個匿名函式,因為標準里注明了若 then() 方法里面的引數不是函式則什么都不錯,所以 catch(rejectionFn) 其實就是 then(null, rejectionFn) 的別名,

    anAsyncFn().then(
      resolveSuccess,
      rejectError
    )
    

    在以上代碼中,anAsyncFn() 拋出來的錯誤 rejectError 會正常接住,但是 resolveSuccess 拋出來的錯誤將無法捕獲,所以更好的做法是永遠使用 catch

    anAsyncFn()
      .then(resolveSuccess)
      .catch(rejectError)
    

    倘若講究一點,也可以通過 resolveSuccess 來捕獲 anAsyncFn() 的錯誤,catch 捕獲 resolveSuccess 的錯誤,

    anAsyncFn()
      .then(
        resolveSuccess,
        rejectError
      )
      .catch(handleError)
    
  2. 通過全域屬性監聽未被處理的 Promise 錯誤,

    瀏覽器環境(window)的拒絕狀態監聽事件:

    • unhandledrejection 當 Promise 被拒絕,并且沒有提供拒絕處理程式時,觸發該事件,
    • rejectionhandled 當 Promise 被拒絕時,若拒絕處理程式被呼叫,觸發該事件,
    // 初始化串列
    const unhandledRejections = new Map()
    // 監聽未處理拒絕狀態
    window.addEventListener('unhandledrejection', e => {
      unhandledRejections.set(e.promise, e.reason)
    })
    // 監聽已處理拒絕狀態
    window.addEventListener('rejectionhandled', e => {
      unhandledRejections.delete(e.promise)
    })
    // 回圈處理拒絕狀態
    setInterval(() => {
      unhandledRejections.forEach((reason, promise) => {
        console.log('handle: ', reason.message)
        promise.catch(e => {
          console.log(`I catch u!`, e.message)
        })
      })
      unhandledRejections.clear()
    }, 5000)
    

注意:Promise.reject()new Promise((resolve, reject) => reject()) 這種方式不能直接觸發 unhandledrejection 事件,必須是滿足已經進行了 then() 鏈式呼叫的 Promise 物件才行,

2.6 取消一個 Promise

當執行一個超級久的異步請求時,若超過了能夠忍受的最大時長,往往需要取消此次請求,但是 Promise 并沒有類似于 cancel() 的取消方法,想結束一個 Promise 只能通過 resolvereject 來改變其狀態,社區已經有了滿足此需求的開源庫 Speculation,

或者利用 Promise.race() 的機制來同時注入一個會超時的異步函式,但是 Promise.race() 結束后主程式其實還在 pending 中,占用的資源并沒有釋放,

Promise.race([anAsyncFn(), timeout(5000)])

2.7 迭代器的應用

若想按順序執行一堆異步程式,可使用 reduce,每次遍歷回傳一個 Promise 物件,在下一輪 await 住從而依次執行,

function wasteTime (ms) {
    return new Promise(resolve => setTimeout(() => {
        resolve(ms)
        console.log('waste', ms)
    }, ms))
}

// 依次浪費 3 4 5 3 秒 === 15 秒
const arr = [3000, 4000, 5000, 3000]
arr.reduce(async (last, curr) => {
    await last
    return wasteTime(curr)
}, undefined)

三、總結

  1. 每當要使用異步代碼時,請考慮使用 Promise
  2. Promise 中所有方法的回傳型別都是 Promise
  3. Promise 中的狀態改變是一次性的,建議在 reject() 方法中傳遞 Error 物件,
  4. 確保為所有的 Promise 添加 then()catch() 方法,
  5. 使用 Promise.all() 行運行多個 Promise
  6. 倘若想在 then()catch() 后都做點什么,可使用 finally()
  7. 可以將多個 then() 掛載在同一個 Promise 上,
  8. async (異步)函式回傳一個 Promise,所有回傳 Promise 的函式也可以被視作一個異步函式,
  9. await 用于呼叫異步函式,直到其狀態改變(fulfilled or rejected),
  10. 使用 async / await 時要考慮背景關系的依賴性,避免造成不必要的阻塞,

更多文章訪問我的博客

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/47807.html

標籤:JavaScript

上一篇:JavaScript中陣列去重的幾種方法

下一篇:利用 React 高階組件實作一個面包屑導航

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more