溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Promise和Generato中如何用同步方法寫(xiě)異步JavaScript

發(fā)布時(shí)間:2021-11-16 17:45:41 來(lái)源:億速云 閱讀:116 作者:柒染 欄目:web開(kāi)發(fā)

這篇文章給大家介紹Promise和Generato中如何用同步方法寫(xiě)異步JavaScript,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助。

最近在寫(xiě)一個(gè)自己的網(wǎng)站的時(shí)候(可以觀摩一下~Colors),在無(wú)意識(shí)中用callback寫(xiě)了一段嵌套了5重回調(diào)函數(shù)的可怕的代碼。回過(guò)神來(lái)的時(shí)候被自己嚇了一跳,這可不行啊,丑得沒(méi)法看啊!于是打算嘗試一下一些流行的異步的解決方案。經(jīng)過(guò)一番折騰之后...我終于找到了一個(gè)令自己滿意的方案了(愛(ài)不釋手)。

1. JavaScript異步解決方案有哪一些

其實(shí)異步JavaScript已經(jīng)不是什么高級(jí)的東西了,Nodejs的出現(xiàn),特別是callback  hell令人恐懼的寫(xiě)法已經(jīng)成功倒逼出了很多很棒的解決方案。在這里看尤雨溪大神的這篇小短文,非常精簡(jiǎn)扼要地介紹了當(dāng)前常用的async.js, Promise,  co, async/await。個(gè)人建議有機(jī)會(huì)可以都試一下看看。而從個(gè)人的角度,我可能會(huì)以以下的標(biāo)準(zhǔn)來(lái)選擇(個(gè)人喜好):

需要寫(xiě)爬蟲(chóng)之類(lèi)控制并發(fā)數(shù)的我會(huì)用async.js;它的有一些API還是很方便的。

寫(xiě)前端的代碼的時(shí)候可能會(huì)比較傾向于考慮Promise,因?yàn)橐话銇?lái)說(shuō)前端的異步場(chǎng)景除了ajax之外貌似也不是很多了。而且之前使用過(guò)isomorphic-fetch,感覺(jué)很棒。

后端代碼nodejs,那就非co莫屬了。根據(jù)尤雨溪大神的說(shuō)法,es7的async/await也只是Promise &  Generator的語(yǔ)法糖而已。而co,就是結(jié)合了Promise和Generator的神一般的庫(kù)。而本篇文章主要就是講co結(jié)合Promise和Generator的異步解決方法。

2. Promise & Generator簡(jiǎn)單入門(mén)

ES6是個(gè)好東西,其中的Promise和Generator可以說(shuō)是精華的部分之一了。下面簡(jiǎn)單介紹入門(mén)一下Promise以及Generator。這一小節(jié)的介紹會(huì)很簡(jiǎn)單,而且也只是這兩個(gè)新特性的一部分,但是提到的點(diǎn)都是本篇文章所需要的。當(dāng)然,從學(xué)習(xí)的角度,應(yīng)該找書(shū)去完全了解一下這兩個(gè)特性,起碼有個(gè)印象吧~個(gè)人感覺(jué)ES6的學(xué)習(xí)可以去讀NCZ的Understanding  ECMAScript6或者阮一峰大神的ES6標(biāo)準(zhǔn)入門(mén),都有電子書(shū),很棒!前者語(yǔ)言比較淺顯易懂,生動(dòng)有趣,后者會(huì)更加詳細(xì),有條理一些。如果您已經(jīng)對(duì)這些特性了如指掌的話,那就不用看這一小節(jié)了~

2.1 Promise

Promise有很多版本,也有很多實(shí)現(xiàn)的庫(kù),但是這里主要是介紹ES6標(biāo)準(zhǔn)的內(nèi)容。如果閱讀以下幾條特性覺(jué)得不懂的話建議先看看上面兩本書(shū)相應(yīng)的章節(jié)。

關(guān)于promise,首先要意識(shí)到它是一種對(duì)象。這種對(duì)象可以用Promise構(gòu)造函數(shù)來(lái)創(chuàng)建,也可以通過(guò)Nodejs本身一些默認(rèn)的返回來(lái)獲取這種對(duì)象。

promise對(duì)象有三種狀態(tài):Pending,F(xiàn)ulfilled,Rejected。分別對(duì)應(yīng)著未開(kāi)始的狀態(tài),成功的狀態(tài),以及失敗的狀態(tài)。

這種對(duì)象常常封裝著異步的方法。在異步方法里面,通過(guò)resolve和reject來(lái)劃定什么時(shí)候算是成功,什么時(shí)候算是錯(cuò)誤,同時(shí)傳參數(shù)給這兩個(gè)函數(shù)。這些參數(shù)就是異步得到的結(jié)果或者錯(cuò)誤。

異步有成功的時(shí)候,也有錯(cuò)誤的時(shí)候。對(duì)象通過(guò)then和catch方法來(lái)規(guī)定異步結(jié)束之后的操作(正確處理函數(shù)/錯(cuò)誤處理函數(shù))。而then和catch是Promise.prototype上的函數(shù),因此“實(shí)例化”之后(其實(shí)并非真正的實(shí)例)可以直接使用。

這個(gè)promise對(duì)象還有一個(gè)神奇的地方,就是可以級(jí)聯(lián)。每一個(gè)then里面返回一個(gè)promise對(duì)象,就又像上面所提的那樣,有異步就等待異步,然后選擇出規(guī)定好的正確處理函數(shù)還是錯(cuò)誤處理函數(shù)。

2.2 Generator

Generator函數(shù)是一個(gè)帶星星函數(shù),而且是一個(gè)可以暫停的函數(shù)。

函數(shù)的內(nèi)部通過(guò)yield來(lái)推進(jìn)函數(shù)。通過(guò)定義yield后面的值來(lái)決定返回的value。

函數(shù)返回一個(gè)遍歷器,這個(gè)遍歷器有一個(gè)next方法,可以獲取一個(gè)對(duì)象,這個(gè)對(duì)象就包含了yield定義好的參數(shù)。

關(guān)于ES6的知識(shí)的其它特性就不談了,對(duì)寫(xiě)同(yi)步代碼的話掌握以上這些已經(jīng)足夠了。

3. Co

噔噔噔噔!神奇的Co登場(chǎng)了!這是一個(gè)tj大神寫(xiě)的庫(kù)。使用方法很簡(jiǎn)單,在Github上的README也講得很清楚了。主要就是兩點(diǎn):

Co函數(shù)里面包裹一個(gè)generator函數(shù),在generator函數(shù)里面可以yield  promise對(duì)象,從而達(dá)到異步的目的。在Co的內(nèi)部實(shí)現(xiàn)里面是通過(guò)遞歸調(diào)用next函數(shù),把每一個(gè)promise的值返回出來(lái),從而實(shí)現(xiàn)異步轉(zhuǎn)“同步”的寫(xiě)法。

Co函數(shù)返回一個(gè)promise對(duì)象,可以調(diào)用then,catch方法來(lái)對(duì)Generator函數(shù)返回的結(jié)果進(jìn)行傳遞。方便進(jìn)行后續(xù)的成功處理或者錯(cuò)誤處理。

4. 如何用同步的寫(xiě)法寫(xiě)異步的代碼

下面展示一段異步處理的代碼,可以看到,同步的寫(xiě)法寫(xiě)異步真的很爽...

function *foo(res, name, newPassword, oldPassword) {   try {     // yield一個(gè)promise對(duì)象,如果有錯(cuò)誤就會(huì)被后面的catch捕捉到,成功就會(huì)返回user。     const user = yield new Promise(function(resolve, reject) {       // 常見(jiàn)的數(shù)據(jù)庫(kù)讀取星系       User.get(name, function(err, user) {         if(err) reject(err)         resolve(user)       })     })      if(user.password != oldPassword) {       return res.send({errorMsg:"密碼輸入錯(cuò)誤!"})     }      // 看到這一個(gè)異步函數(shù)和上一個(gè)的異步在寫(xiě)法上是基本上“同步”的,沒(méi)有了相互嵌套,很優(yōu)雅~也更加方便了debug~     yield new Promise(function(resolve, reject) {       User.update(name, newPassword, function(err) {         if(err) reject(err)         res.send({msg: "你成功更換密碼了!"})         resolve()       })     })    } catch(e) {     console.log("Error:", e)     return res.send({errorMsg:"Setting Fail!"})   } }  // 使用的話就直接調(diào)用co包含對(duì)應(yīng)的Generator函數(shù)即可。 co(foo(res, name, newPassword, oldPassword))

關(guān)于Promise和Generato中如何用同步方法寫(xiě)異步JavaScript就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI