成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

從源碼看 Promise 概念與實(shí)現(xiàn)

kel / 1030人閱讀

摘要:從源碼看概念與實(shí)現(xiàn)是異步編程中的重要概念,它較好地解決了異步任務(wù)中回調(diào)嵌套的問(wèn)題。這些概念中有趣的地方在于,標(biāo)識(shí)狀態(tài)的變量如都是形容詞,用于傳入數(shù)據(jù)的接口如與都是動(dòng)詞,而用于傳入回調(diào)函數(shù)的接口如及則在語(yǔ)義上用于修飾動(dòng)詞的副詞。

從源碼看 Promise 概念與實(shí)現(xiàn)

Promise 是 JS 異步編程中的重要概念,它較好地解決了異步任務(wù)中回調(diào)嵌套的問(wèn)題。在沒(méi)有引入新的語(yǔ)言機(jī)制的前提下,這是如何實(shí)現(xiàn)的呢?上手 Promise 時(shí)常見(jiàn)若干晦澀的 API 與概念,它們又為什么存在呢?源碼里隱藏著這些問(wèn)題的答案。

下文會(huì)在介紹 Promise 概念的基礎(chǔ)上,以一步步代碼實(shí)現(xiàn) Promise 的方式,解析 Promise 的實(shí)現(xiàn)機(jī)制。相應(yīng)代碼參考來(lái)自 PromiseJS 博客 及 You don’t know JS 的若干章節(jié)。

Why Promise
(有使用 Promise 經(jīng)驗(yàn)的讀者可忽略本段)

基于 JS 函數(shù)一等公民的優(yōu)良特性,JS 中最基礎(chǔ)的異步邏輯一般是以向異步 API 傳入一個(gè)函數(shù)的方式實(shí)現(xiàn)的,這個(gè)函數(shù)里包含了異步完成后的后續(xù)業(yè)務(wù)邏輯。與普通的函數(shù)參數(shù)不同的是,這類(lèi)函數(shù)需在異步操作完成時(shí)才被調(diào)用,故而稱之為回調(diào)函數(shù)。以異步 Ajax 查詢?yōu)槔诨卣{(diào)的代碼實(shí)現(xiàn)可能是這樣的:

ajax.get("xxx", data => {
 // 在回調(diào)函數(shù)里獲取到數(shù)據(jù),執(zhí)行后續(xù)邏輯
 console.log(data)
 // ...
})

從而,在需要多個(gè)異步操作依次執(zhí)行時(shí),就需要以回調(diào)嵌套的方式來(lái)實(shí)現(xiàn),例如這樣:

ajax.get("xxx", dataA => {
 // 第一個(gè)請(qǐng)求完成后,依賴其獲取到的數(shù)據(jù)發(fā)送第二個(gè)請(qǐng)求
 // 產(chǎn)生回調(diào)嵌套
 ajax.get("yyy" + dataA, dataB => {
 console.log(dataB)
 // ...
 })
})

這樣一來(lái),在處理越多的異步邏輯時(shí),就需要越深的回調(diào)嵌套,這種編碼模式的問(wèn)題主要有以下幾個(gè):

代碼邏輯書(shū)寫(xiě)順序與執(zhí)行順序不一致,不利于閱讀與維護(hù)。
異步操作的順序變更時(shí),需要大規(guī)模的代碼重構(gòu)。
回調(diào)函數(shù)基本都是匿名函數(shù),bug 追蹤困難。
回調(diào)函數(shù)是被第三方庫(kù)代碼(如上例中的 ajax )而非自己的業(yè)務(wù)代碼所調(diào)用的,造成了 IoC 控制反轉(zhuǎn)。
其中看似最無(wú)關(guān)緊要的控制反轉(zhuǎn),實(shí)際上是純回調(diào)編碼模式的最大問(wèn)題。 由于回調(diào)函數(shù)是被第三方庫(kù)調(diào)用的,因此回調(diào)中的代碼無(wú)法預(yù)期自己被執(zhí)行時(shí)的環(huán)境 ,這可能導(dǎo)致:

回調(diào)被執(zhí)行了多次
回調(diào)一次都沒(méi)有被執(zhí)行
回調(diào)不是異步執(zhí)行而是被同步執(zhí)行
回調(diào)被過(guò)早或過(guò)晚執(zhí)行
回調(diào)中的報(bào)錯(cuò)被第三方庫(kù)吞掉
……
通過(guò)【防御性編程】的概念,上述問(wèn)題其實(shí)都可以通過(guò)在回調(diào)函數(shù)內(nèi)部進(jìn)行各種檢查來(lái)逐一避免,但這毫無(wú)疑問(wèn)地會(huì)嚴(yán)重影響代碼的可讀性與開(kāi)發(fā)效率。這種異步編碼模式存在的諸多問(wèn)題,也就是臭名昭著的【回調(diào)地獄】了。

Promise 較好地解決了這個(gè)問(wèn)題。以上例中的異步 ajax 邏輯為例,基于 Promise 的模式是這樣的:

// 將 ajax 請(qǐng)求封裝為一個(gè)返回 Promise 的函數(shù)
function getData (){
 return new Promise((resolve, reject) => {
 ajax.get("xxx", data => {
 resolve(data)
 })
 })
}

// 調(diào)用該函數(shù)并在 Promise 的 then 接口中獲取數(shù)據(jù)
getData().then(data => {
 console.log(data)
})

看起來(lái)變得啰嗦了?但在上例中需要嵌套回調(diào)的情況,可以改寫(xiě)成下面的形式:

function getDataA (){
 return new Promise((resolve, reject) => {
 ajax.get("xxx", dataA => {
 resolve(dataA)
 })
 })
}

function getDataB (dataA){
 return new Promise((resolve, reject) => {
 ajax.get("yyy" + dataA, dataB => {
 resolve(dataB)
 })
 })
}

// 使用鏈?zhǔn)秸{(diào)用解開(kāi)回調(diào)嵌套
getDataA()
 .then(dataA => getDataB(dataA))
 .then(dataB => console.log(dataB))

這就解決了異步邏輯的回調(diào)嵌套問(wèn)題。那么問(wèn)題來(lái)了,這樣優(yōu)雅的 API 是如何實(shí)現(xiàn)的呢?

基礎(chǔ)概念
非?;\統(tǒng)地說(shuō),Promise 其實(shí)應(yīng)驗(yàn)了 CS 的名言【所有問(wèn)題都可以通過(guò)加一層中間層來(lái)解決】。在上面回調(diào)嵌套的問(wèn)題中,Promise 就充當(dāng)了一個(gè)中間層,用來(lái)【把回調(diào)造成的控制反轉(zhuǎn)再反轉(zhuǎn)回去】。在使用 Promise 的例子中,控制流分為了兩個(gè)部分:觸發(fā)異步前的邏輯通過(guò) new傳入 Promise,而異步操作完成后的邏輯則傳入 Promise 的 then 接口中。通過(guò)這種方式,第一方業(yè)務(wù)和第三方庫(kù)的相應(yīng)邏輯都由 Promise 來(lái)調(diào)用,進(jìn)而在 Promise 中解決異步編程中可能出現(xiàn)的各種問(wèn)題。

這種模式其實(shí)和觀察者模式是接近的。下面的代碼將 resolve / then 換成了 publish / subscribe ,將通過(guò) new Promise 生成的 Promise 換成了通過(guò) observe 生成的 observable 實(shí)例??梢园l(fā)現(xiàn),這種調(diào)用同樣做到了回調(diào)嵌套的解耦。這就是 Promise 魔法的關(guān)鍵之一。

// observe 相當(dāng)于 new Promise
// publish 相當(dāng)于 resolve
let observable = observe(publish => {
 ajax.get("xxx", data => {
 // ...
 publish(data)
 })
})

// subscribe 相當(dāng)于 then
observable.subscribe(data => {
 console.log(data)
 // ...
})

到這個(gè)例子為止,都還沒(méi)有涉及 Promise 的源碼實(shí)現(xiàn)。在進(jìn)一步深入前,有必要列出在 Promise 中常見(jiàn)的相關(guān)概念:

resolve / reject : 作為 Promise 暴露給第三方庫(kù)的 API 接口,在異步操作完成時(shí)由第三方庫(kù)調(diào)用,從而改變 Promise 的狀態(tài)。
fulfilled / rejected / pending : 標(biāo)識(shí)了一個(gè) Promise 當(dāng)前的狀態(tài)。
then / done : 作為 Promise 暴露給第一方代碼的接口,在此傳入【原本直接傳給第三方庫(kù)】的回調(diào)函數(shù)。
這些概念中有趣的地方在于,標(biāo)識(shí)狀態(tài)的變量(如 fulfilled / rejected / pending )都是形容詞,用于傳入數(shù)據(jù)的接口(如 resolve 與 reject )都是動(dòng)詞,而用于傳入回調(diào)函數(shù)的接口(如 then 及 done )則在語(yǔ)義上用于修飾動(dòng)詞的副詞。在閱讀源碼的時(shí)候,除了變量的類(lèi)型外,其名稱所對(duì)應(yīng)的詞性也能對(duì)理解代碼邏輯起到幫助,例如:

標(biāo)識(shí)數(shù)據(jù)的變量與 OO 對(duì)象常用名詞( result / data / Promise )
標(biāo)識(shí)狀態(tài)的變量常用形容詞( fulfilled / pending )
被調(diào)用的函數(shù)接口常用動(dòng)詞( resolve / reject )
用于傳入函數(shù)的參數(shù)接口常用副詞(如 then / onFulfilled 等,畢竟函數(shù)常用動(dòng)詞,而副詞本來(lái)就是用來(lái)修飾動(dòng)詞的)
預(yù)熱了 Promise 相關(guān)的變量名后,就可以開(kāi)始實(shí)現(xiàn) Promise 了。下文的行文方式既不是按行號(hào)逐行介紹,也不是按代碼執(zhí)行順序來(lái)回跳躍,而是按照實(shí)際編碼時(shí)的步驟一步步地搭建出相應(yīng)的功能。相信這種方式比直接在源碼里堆注釋能更為友好一些。

狀態(tài)機(jī)
一個(gè) Promise 可以理解為一個(gè)狀態(tài)機(jī),相應(yīng)的 API 接口要么用于改變狀態(tài)機(jī)的狀態(tài),要么在到達(dá)某個(gè)狀態(tài)時(shí)被觸發(fā)。因此首先需要實(shí)現(xiàn)的,是 Promise 的狀態(tài)信息:

const PENDING = 0
const FULFILLED = 1
const REJECTED = 2

function Promise (){
 // 存儲(chǔ)該 Promise 的狀態(tài)信息
 let state = PENDING

 // 存儲(chǔ) FULFILLED 或 REJECTED 時(shí)帶來(lái)的數(shù)據(jù)
 let value = null

 // 存儲(chǔ) then 或 done 時(shí)調(diào)用的成功或失敗回調(diào)
 var handlers = []
}

狀態(tài)遷移
指定狀態(tài)機(jī)的狀態(tài)后,可以實(shí)現(xiàn)基本的狀態(tài)遷移功能,即 fulfill 與 reject 這兩個(gè)用于改變狀態(tài)的函數(shù),相應(yīng)實(shí)現(xiàn)也十分簡(jiǎn)單:

const PENDING = 0
const FULFILLED = 1
const REJECTED = 2

function Promise (){
 // 存儲(chǔ)該 Promise 的狀態(tài)信息
 let state = PENDING

 // 存儲(chǔ) FULFILLED 或 REJECTED 時(shí)帶來(lái)的數(shù)據(jù)
 let value = null

 // 存儲(chǔ) then 或 done 時(shí)調(diào)用的成功或失敗回調(diào)
 let handlers = []
 
 function fulfill (result){
 state = FULFILLED
 value = result
 }

 function reject (error){
 state = REJECTED
 value = error
 }
}

在這兩種底層的狀態(tài)遷移基礎(chǔ)上,我們需要實(shí)現(xiàn)一種更高級(jí)的狀態(tài)遷移方式,這就是 resolve了:

const PENDING = 0
const FULFILLED = 1
const REJECTED = 2

function Promise (){
 // 存儲(chǔ)該 Promise 的狀態(tài)信息
 let state = PENDING

 // 存儲(chǔ) FULFILLED 或 REJECTED 時(shí)帶來(lái)的數(shù)據(jù)
 let value = null

 // 存儲(chǔ) then 或 done 時(shí)調(diào)用的成功或失敗回調(diào)
 let handlers = []
 
 function fulfill (result){
 state = FULFILLED
 value = result
 }

 function reject (error){
 state = REJECTED
 value = error
 }

 function resolve (result){
 try {
 let then = getThen(result)
 if (then) {
 // 遞歸 resolve 待解析的 Promise
 doResolve(then.bind(result), resolve, reject)
 return
 }
 fulfill(result)
 } catch (e) {
 reject(e)
 }
 }
}

resolve 既可以接受一個(gè) Promise,也可以接受一個(gè)基本類(lèi)型。當(dāng) resolve 一個(gè) Promise 時(shí),就使用 doResolve 輔助函數(shù)來(lái)執(zhí)行這個(gè) Promise 并等待其完成。通過(guò)暴露 resolve 而隱藏底層的 fulfill 接口,從而保證了一個(gè) Promise 一定不會(huì)被另一個(gè) Promise 所 fulfill 。在這個(gè)過(guò)程中所用到的輔助函數(shù)如下:

/**
 * 檢查一個(gè)值是否為 Promise
 * 若為 Promise 則返回該 Promise 的 then 方法
 *
 * @param {Promise|Any} value
 * @return {Function|Null}
 */
function getThen (value){
 let t = typeof value
 if (value && (t === "object" || t === "function")) {
 const then = value.then
 // 可能需要更復(fù)雜的 thenable 判斷
 if (typeof then === "function") return then
 }
 return null
}

/**
 * 傳入一個(gè)需被 resolve 的函數(shù),該函數(shù)可能存在不確定行為
 * 確保 onFulfilled 與 onRejected 只會(huì)被調(diào)用一次
 * 在此不保證該函數(shù)一定會(huì)被異步執(zhí)行
 *
 * @param {Function} fn 不能信任的回調(diào)函數(shù)
 * @param {Function} onFulfilled
 * @param {Function} onRejected
 */
function doResolve (fn, onFulfilled, onRejected){
 let done = false
 try {
 fn(function (value){
 if (done) return
 done = true
 // 執(zhí)行由 resolve 傳入的 resolve 回調(diào)
 onFulfilled(value)
 }, function (reason){
 if (done) return
 done = true
 onRejected(reason)
 })
 } catch (ex) {
 if (done) return
 done = true
 onRejected(ex)
 }
}

resolve 接口
在完整完成了內(nèi)部狀態(tài)機(jī)的基礎(chǔ)上,還需要向用戶暴露用于傳入第一方代碼的 new Promise接口,及傳入異步操作回調(diào)的 done / then 接口。下面從 resolve 一個(gè) Promise 開(kāi)始:

const PENDING = 0
const FULFILLED = 1
const REJECTED = 2

function Promise (fn){
 // 存儲(chǔ)該 Promise 的狀態(tài)信息
 let state = PENDING

 // 存儲(chǔ) FULFILLED 或 REJECTED 時(shí)帶來(lái)的數(shù)據(jù)
 let value = null

 // 存儲(chǔ) then 或 done 時(shí)調(diào)用的成功或失敗回調(diào)
 let handlers = []
 
 function fulfill (result){
 state = FULFILLED
 value = result
 }

 function reject (error){
 state = REJECTED
 value = error
 }

 function resolve (result){
 try {
 let then = getThen(result)
 if (then) {
 // 遞歸 resolve 待解析的 Promise
 doResolve(then.bind(result), resolve, reject)
 return
 }
 fulfill(result)
 } catch (e) {
 reject(e)
 }
 }
 
 doResolve(fn, resolve, reject)
}

可以發(fā)現(xiàn)這里重用了 doResolve 以執(zhí)行不被信任的 fn 函數(shù)。這個(gè) fn 函數(shù)可以多次調(diào)用 resolve 和 reject 接口,甚至拋出異常,但 Promise 中對(duì)其進(jìn)行了限制,保證每個(gè) Promise 只能被 resolve 一次,且在 resolve 后不再發(fā)生狀態(tài)轉(zhuǎn)移。

觀察者 done 接口
到此為止已經(jīng)完成了一個(gè)完整的狀態(tài)機(jī),但仍然沒(méi)有暴露出一個(gè)合適的方法來(lái)觀察其狀態(tài)的變更。我們的最終目標(biāo)是實(shí)現(xiàn) then 接口,但由于實(shí)現(xiàn) done 接口的語(yǔ)義要容易得多,因此可首先實(shí)現(xiàn) done 。

下面的例子中要實(shí)現(xiàn)的是 promise.done(onFulfilled, onRejected) 接口,使得:

onFulfilled 與 onRejected 二者只有一個(gè)被調(diào)用。
該接口只會(huì)被調(diào)用一次。
該接口總是被異步執(zhí)行。
調(diào)用 done 的執(zhí)行時(shí)機(jī)與調(diào)用時(shí) Promise 是否已 resolved 無(wú)關(guān)。

const PENDING = 0
const FULFILLED = 1
const REJECTED = 2

function Promise (fn){
 // 存儲(chǔ)該 Promise 的狀態(tài)信息
 let state = PENDING

 // 存儲(chǔ) FULFILLED 或 REJECTED 時(shí)帶來(lái)的數(shù)據(jù)
 let value = null

 // 存儲(chǔ) then 或 done 時(shí)調(diào)用的成功或失敗回調(diào)
 let handlers = []
 
 function fulfill (result){
 state = FULFILLED
 handlers.forEach(handle)
 handlers = null
 }

 function reject (error){
 state = REJECTED
 value = error
 handlers.forEach(handle)
 handlers = null
 }

 function resolve (result){
 try {
 let then = getThen(result)
 if (then) {
 // 遞歸 resolve 待解析的 Promise
 doResolve(then.bind(result), resolve, reject)
 return
 }
 fulfill(result)
 } catch (e) {
 reject(e)
 }
 }
 
 // 保證 done 中回調(diào)的執(zhí)行
 function handle (handler){
 if (state === PENDING) {
 handlers.push(handler)
 } else {
 if (state === FULFILLED &&
 typeof handler.onFulfilled === "function") {
 handler.onFulfilled(value)
 }
 if (state === REJECTED &&
 typeof handler.onRejected === "function") {
 handler.onRejected(value)
 }
 }
 }
 
 this.done = function (onFulfilled, onRejected){
 // 保證 done 總是異步執(zhí)行
 setTimeout(function (){
 handle({
 onFulfilled: onFulfilled,
 onRejected: onRejected
 })
 }, 0)
 }
 
 doResolve(fn, resolve, reject)
}

從而在 Promise 的狀態(tài)遷移至 resolved 或 rejected 時(shí),所有通過(guò) done 注冊(cè)的觀察者 handler 都能被執(zhí)行。并且這個(gè)操作總是在下一個(gè) tick 異步執(zhí)行的。

觀察者 then 方法
在實(shí)現(xiàn)了 done 方法的基礎(chǔ)上,就可以實(shí)現(xiàn) then 方法了。它們沒(méi)有本質(zhì)的區(qū)別,但 then 能夠返回一個(gè)新的 Promise:

this.then = function (onFulfilled, onRejected){
 const _this = this
 return new Promise(function (resolve, reject){
 return _this.done(function (result){
 if (typeof onFulfilled === "function") {
 try {
 return resolve(onFulfilled(result))
 } catch (ex) {
 return reject(ex)
 }
 } else return resolve(result)
 }, function (error){
 if (typeof onRejected === "function") {
 try {
 return resolve(onRejected(error))
 } catch (ex) {
 return reject(ex)
 }
 } else return reject(error)
 })
 })
}

最后梳理一下典型場(chǎng)景下 Promise 的執(zhí)行流程。以一個(gè) ajax 請(qǐng)求的異步場(chǎng)景為例,整個(gè)異步邏輯分為兩部分:調(diào)用 ajax 庫(kù)的代碼及異步操作完成時(shí)的代碼。前者被放入 Promise 的構(gòu)造函數(shù)中,由 doResolve 方法執(zhí)行,在這部分業(yè)務(wù)邏輯通過(guò)調(diào)用 resolve 與 reject 接口,在異步操作完成時(shí)改變 Promise 的狀態(tài),從而調(diào)用后者,即調(diào)用 Promise 中通過(guò) then 接口傳入的 onFulfilled 與 onRejected 后續(xù)業(yè)務(wù)邏輯代碼。這個(gè)過(guò)程中, doResolve 對(duì)第三方 ajax 庫(kù)的各種異常行為(多次調(diào)用回調(diào)或拋出異常)做了限制,而 then 下隱藏的 done 則封裝了 handle 接口,保證了多個(gè)通過(guò) then 傳入的 handler 總是異步執(zhí)行,并能得到合適的返回結(jié)果。由于then 中的代碼總是異步執(zhí)行并返回了一個(gè)新的 Promise,因此可以通過(guò)鏈?zhǔn)秸{(diào)用的方式來(lái)串聯(lián)多個(gè) then 方法,從而實(shí)現(xiàn)異步操作的鏈?zhǔn)秸{(diào)用。

總結(jié)
閱讀了 Promise 的代碼實(shí)現(xiàn)后可以發(fā)現(xiàn),它的魔法來(lái)自于將【函數(shù)一等公民】和【遞歸】的結(jié)合。一個(gè) resolve 如果獲得的結(jié)果還是一個(gè) Promise,那么就將遞歸地繼續(xù) resolve 這個(gè) Promise。同時(shí),Promise 的輔助函數(shù)中解決了諸多異步編程時(shí)的常見(jiàn)問(wèn)題,如回調(diào)的多次調(diào)用及異常處理等。

介紹 Promise 時(shí)不少較為晦澀的 API 其實(shí)也來(lái)自于對(duì) Promise 編碼實(shí)現(xiàn)時(shí)的涉及的若干底層功能。例如, fulfilled 這個(gè)概念就被封裝在了 resolve 下,而 done 方法則是 then 方法的依賴等。這些概念在 Promise 的演化中被封裝在了通用的 API 下,只有在閱讀源碼時(shí)才會(huì)用到。Promise 的 API 設(shè)計(jì)也是簡(jiǎn)潔的,其接口命名和英語(yǔ)的詞性也有相當(dāng)大的聯(lián)系,這也有利于理解代碼實(shí)現(xiàn)的相應(yīng)功能。

除了上文中從狀態(tài)機(jī)的角度理解 Promise 以外,其實(shí)還可以從函數(shù)式編程的角度來(lái)理解這個(gè)模式。可以將 Promise 看做一個(gè)封裝了異步數(shù)據(jù)的 Monad,其 then 接口就相當(dāng)于這個(gè) Monad 的map 方法。這樣一來(lái),Promise 也可以理解為一個(gè)特殊的對(duì)象,這個(gè)對(duì)象【通過(guò)一個(gè)函數(shù)獲取數(shù)據(jù),并通過(guò)另一個(gè)函數(shù)來(lái)操作數(shù)據(jù)】,用戶并不需要關(guān)心其中潛在的異步風(fēng)險(xiǎn),只需要提供相應(yīng)的函數(shù)給 Promise API 即可(這展開(kāi)又是一篇長(zhǎng)文了)。

希望本文對(duì) Promise 的分析對(duì)理解異步編程有所幫助

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/107940.html

相關(guān)文章

  • JavaScript 異步

    摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。寫(xiě)一個(gè)符合規(guī)范并可配合使用的寫(xiě)一個(gè)符合規(guī)范并可配合使用的理解的工作原理采用回調(diào)函數(shù)來(lái)處理異步編程。 JavaScript怎么使用循環(huán)代替(異步)遞歸 問(wèn)題描述 在開(kāi)發(fā)過(guò)程中,遇到一個(gè)需求:在系統(tǒng)初始化時(shí)通過(guò)http獲取一個(gè)第三方服務(wù)器端的列表,第三方服務(wù)器提供了一個(gè)接口,可通過(guò)...

    tuniutech 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開(kāi)始的到封裝后的都在試圖解決異步編程過(guò)程中的問(wèn)題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門(mén)的全稱是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開(kāi)發(fā)的科普類(lèi)文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門(mén)教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評(píng)論0 收藏0
  • 瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制最全面的一次梳理

    摘要:如果看完本文后,還對(duì)進(jìn)程線程傻傻分不清,不清楚瀏覽器多進(jìn)程瀏覽器內(nèi)核多線程單線程運(yùn)行機(jī)制的區(qū)別。因此準(zhǔn)備梳理這塊知識(shí)點(diǎn),結(jié)合已有的認(rèn)知,基于網(wǎng)上的大量參考資料,從瀏覽器多進(jìn)程到單線程,將引擎的運(yùn)行機(jī)制系統(tǒng)的梳理一遍。 前言 見(jiàn)解有限,如有描述不當(dāng)之處,請(qǐng)幫忙及時(shí)指出,如有錯(cuò)誤,會(huì)及時(shí)修正。 ----------超長(zhǎng)文+多圖預(yù)警,需要花費(fèi)不少時(shí)間。---------- 如果看完本文后,還...

    wanghui 評(píng)論0 收藏0
  • 【自己讀源碼】Netty4.X系列(三) Channel Register

    摘要:我想這很好的解釋了中,僅僅一個(gè)都這么復(fù)雜,在單線程或者說(shuō)串行的程序中,編程往往是很簡(jiǎn)單的,說(shuō)白了就是調(diào)用,調(diào)用,調(diào)用然后返回。 Netty源碼分析(三) 前提概要 這次停更很久了,原因是中途迷茫了一段時(shí)間,不過(guò)最近調(diào)整過(guò)來(lái)了。不過(guò)有點(diǎn)要說(shuō)下,前幾天和業(yè)內(nèi)某個(gè)大佬聊天,收獲很多,所以這篇博文和之前也會(huì)不太一樣,我們會(huì)先從如果是我自己去實(shí)現(xiàn)這個(gè)功能需要怎么做開(kāi)始,然后去看netty源碼,與...

    darkbug 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確的學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類(lèi)中文書(shū)籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開(kāi)發(fā)者開(kāi)始使用開(kāi)發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車(chē)的還坐過(guò)站了。大家可以很...

    Edison 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

kel

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<