国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

您的位置:首頁技術(shù)文章
文章詳情頁

淺談JavaScript中的異步處理

瀏覽:90日期:2023-11-12 14:31:40

整理于互聯(lián)網(wǎng)

在 JavaScript 的世界中,所有代碼都是單線程執(zhí)行的 由于這個“缺陷”,導(dǎo)致 JavaScript 的所有網(wǎng)絡(luò)操作,瀏覽器事件,都必須是異步執(zhí)行。異步執(zhí)行可以用回調(diào)函數(shù)實現(xiàn) 異步操作會在將來的某個時間點觸發(fā)一個函數(shù)調(diào)用 主流的異步處理方案主要有:回調(diào)函數(shù) (CallBack) 、 Promise 、 Generator 函數(shù)、 async/await 。 一、回調(diào)函數(shù)(CallBack) 這是異步編程最基本的方法 假設(shè)我們有一個 getData 方法,用于異步獲取數(shù)據(jù),第一個參數(shù)為請求的 url 地址,第二個參數(shù)是回調(diào)函數(shù),如下:

function getData(url, callBack){ // 模擬發(fā)送網(wǎng)絡(luò)請求 setTimeout(()=> {// 假設(shè) res 就是返回的數(shù)據(jù)var res = { url: url, data: Math.random()}// 執(zhí)行回調(diào),將數(shù)據(jù)作為參數(shù)傳遞callBack(res) }, 1000)} 我們預(yù)先設(shè)定一個場景,假設(shè)我們要請求三次服務(wù)器,每一次的請求依賴上一次請求的結(jié)果,如下:

getData(’/page/1?param=123’, (res1) => { console.log(res1) getData(`/page/2?param=${res1.data}`, (res2) => {console.log(res2)getData(`/page/3?param=${res2.data}`, (res3) => { console.log(res3)}) })})

通過上面的代碼可以看出,第一次請求的 url 地址為: /page/1?param=123 ,返回結(jié)果為 res1 。

第二個請求的 url 地址為: /page/2?param=${res1.data} ,依賴第 一次請求的 res1.data ,返回結(jié)果為 res2`。

第三次請求的 url 地址為: /page/3?param=${res2.data} ,依賴第二次請求的 res2.data ,返回結(jié)果為 res3 。

由于后續(xù)請求依賴前一個請求的結(jié)果,所以我們只能把下一次請求寫到上一次請求的回調(diào)函數(shù)內(nèi)部,這樣就形成了常說的:回調(diào)地獄。

二、發(fā)布/訂閱

我們假定,存在一個”信號中心”,某個任務(wù)執(zhí)行完成,就向信號中心”發(fā)布”( publish )一個信號,其他任務(wù)可以向信號中心”訂閱”( subscribe )這個信號,從而知道什么時候自己可以開始執(zhí)行。這就叫做”發(fā)布/訂閱模式”(publish-subscribe pattern),又稱”觀察者模式”(observer pattern)

這個模式有多種實現(xiàn),下面采用的是Ben Alman的 Tiny Pub/Sub ,這是 jQuery 的一個插件 首先, f2 向”信號中心” jQuery 訂閱” done “信號

jQuery.subscribe('done', f2); f1進(jìn)行如下改寫

function f1(){setTimeout(function(){// f1的任務(wù)代碼jQuery.publish('done');}, 1000);} jQuery.publish('done') 的意思是, f1 執(zhí)行完成后,向”信號中心 'jQuery 發(fā)布 'done' 信號,從而引發(fā)f2的執(zhí)行。 此外,f2完成執(zhí)行后,也可以取消訂閱( unsubscribe )

jQuery.unsubscribe('done', f2); 這種方法的性質(zhì)與”事件監(jiān)聽”類似,但是明顯優(yōu)于后者。因為我們可以通過查看”消息中心”,了解存在多少信號、每個信號有多少訂閱者,從而監(jiān)控程序的運行。 三、Promise Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大 所謂 Promise ,簡單說就是一個容器,里面保存著某個未來才會結(jié)束的事件(通常是一個異步操作)的結(jié)果。從語法上說, Promise 是一個對象,從它可以獲取異步操作的消息。 Promise 提供統(tǒng)一的 API ,各種異步操作都可以用同樣的方法進(jìn)行處理 簡單說,它的思想是,每一個異步任務(wù)返回一個 Promise 對象,該對象有一個 then 方法,允許指定回調(diào)函數(shù)。 現(xiàn)在我們使用 Promise 重新實現(xiàn)上面的案例,首先,我們要把異步請求數(shù)據(jù)的方法封裝成 Promise

function getDataAsync(url){ return new Promise((resolve, reject) => {setTimeout(()=> { var res = {url: url,data: Math.random() } resolve(res)}, 1000) })} 那么請求的代碼應(yīng)該這樣寫

getDataAsync(’/page/1?param=123’) .then(res1=> {console.log(res1)return getDataAsync(`/page/2?param=${res1.data}`) }) .then(res2=> {console.log(res2)return getDataAsync(`/page/3?param=${res2.data}`) }) .then(res3=> {console.log(res3) }) then 方法返回一個新的 Promise 對象, then 方法的鏈?zhǔn)秸{(diào)用避免了 CallBack 回調(diào)地獄 但也并不是完美,比如我們要添加很多 then 語句, 每一個 then 還是要寫一個回調(diào)。 如果場景再復(fù)雜一點,比如后邊的每一個請求依賴前面所有請求的結(jié)果,而不僅僅依賴上一次請求的結(jié)果,那會更復(fù)雜。 為了做的更好, async/await 就應(yīng)運而生了,來看看使用 async/await 要如何實現(xiàn) 四、async/await

getDataAsync 方法不變,如下

function getDataAsync(url){ return new Promise((resolve, reject) => {setTimeout(()=> { var res = {url: url,data: Math.random() } resolve(res)}, 1000) })} 業(yè)務(wù)代碼如下

async function getData(){ var res1 = await getDataAsync(’/page/1?param=123’) console.log(res1) var res2 = await getDataAsync(`/page/2?param=${res1.data}`) console.log(res2) var res3 = await getDataAsync(`/page/2?param=${res2.data}`) console.log(res3)} 可以看到使用 asyncawait 就像寫同步代碼一樣 對比 Promise 感覺怎么樣?是不是非常清晰,但是 async/await 是基于 Promise 的,因為使用 async 修飾的方法最終返回一個 Promise , 實際上, async/await 可以看做是使用 Generator 函數(shù)處理異步的語法糖,我們來看看如何使用 Generator 函數(shù)處理異步 五、Generator 首先異步函數(shù)依然是

function getDataAsync(url){ return new Promise((resolve, reject) => {setTimeout(()=> { var res = {url: url,data: Math.random() } resolve(res)}, 1000) })} 使用 Generator 函數(shù)可以這樣寫

function*getData(){ var res1 = yield getDataAsync(’/page/1?param=123’) console.log(res1) var res2 = yield getDataAsync(`/page/2?param=${res1.data}`) console.log(res2) var res3 = yield getDataAsync(`/page/2?param=${res2.data}`) console.log(res3))} 然后我們這樣逐步執(zhí)行

var g = getData()g.next().value.then(res1=> { g.next(res1).value.then(res2=> {g.next(res2).value.then(()=> { g.next()}) })}) 上面的代碼,我們逐步調(diào)用遍歷器的 next() 方法,由于每一個 next() 方法返回值的 value 屬性為一個 Promise 對象 所以我們?yōu)槠涮砑?then 方法, 在 then 方法里面接著運行 next 方法挪移遍歷器指針,直到 Generator 函數(shù)運行完成,實際上,這個過程我們不必手動完成,可以封裝成一個簡單的執(zhí)行器

function run(gen){ var g = gen() function next(data){var res = g.next(data)if (res.done) return res.valueres.value.then((data) => { next(data)}) } next()}

run 方法用來自動運行異步的 Generator 函數(shù),其實就是一個遞歸的過程調(diào)用的過程。這樣我們就不必手動執(zhí)行 Generator 函數(shù)了。 有了 run 方法,我們只需要這樣運行 getData 方法

run(getData)

這樣,我們就可以把異步操作封裝到 Generator 函數(shù)內(nèi)部,使用 run 方法作為 Generator 函數(shù)的自執(zhí)行器,來處理異步。其實我們不難發(fā)現(xiàn), async/await 方法相比于 Generator 處理異步的方式,有很多相似的地方,只不過 async/await 在語義化方面更加明顯,同時 async/await 不需要我們手寫執(zhí)行器,其內(nèi)部已經(jīng)幫我們封裝好了,這就是為什么說 async/await 是 Generator 函數(shù)處理異步的語法糖了

來自:http://blog.poetries.top/2017/08/27/js_cb_promise_generator_async/

標(biāo)簽: JavaScript
相關(guān)文章:
主站蜘蛛池模板: 国产成人综合91精品 | 真人一级一级特黄高清毛片 | 91成人国产| 欧美一级视 | 国产精品亚洲欧美日韩一区在线 | 国产91丝袜美腿在线观看 | 亚洲人成网国产最新在线 | 特级一级毛片视频免费观看 | 日韩欧美一区二区三区免费看 | 成人男男黄网色视频免费 | 欧美一区二区三区视频在线观看 | 9191在线亚洲精品 | 欧美日韩国产一区二区三区播放 | 在线观看自拍视频 | 在线观看va | 亚洲理论片在线中文字幕 | 国产欧美日韩精品在线 | 久久中文字幕日韩精品 | 国产精品爱久久久久久久三级 | 国产毛片a精品毛 | 欧美做a一级视频免费观看 欧美做爱毛片 | 夜色视频一区二区三区 | 国产性夜夜春夜夜爽30 | 中文字幕国产一区 | 一本不卡| 九草在线观看 | 国产精品香蕉一区二区三区 | 欧美videos娇小| 国产精品高清在线观看93 | 免费毛片a线观看 | 国产成人精品一区二区免费 | 国产精品久久亚洲一区二区 | 网站国产 | 中文字幕日韩欧美一区二区三区 | 国产精品合集一区二区 | 欧美日本一道高清二区三区 | 碰碰久久 | 亚洲第一成人天堂第一 | 九九视频免费在线观看 | 日韩欧美久久一区二区 | 国产成人免费手机在线观看视频 |