摘要:實例執(zhí)行以后,可以用方法分別指定狀態(tài)和狀態(tài)的回調(diào)函數(shù)。所以在使用處其中,函數(shù)接受回調(diào)函數(shù),作為對象的狀態(tài)變?yōu)闀r調(diào)用而回調(diào)函數(shù)作為對象的狀態(tài)變?yōu)闀r調(diào)用。
我最近正在看的一本書《聊聊架構》,在進入今天的主題之前,我想和大家分享這本書里的一個概念“生命周期”。
大致是這么說的:
人類的生命很短,百年也只有短短的三萬六千天。大部分人都不愿意接受一切都將消逝的事實,總想活得更久,占有更多,享受更多。在人們短短的一生中,如何延長自身的生命呢?一個辦法就是盡可能做出更多的成就,能夠讓更多的人生活得更好。在同樣的時間內(nèi)創(chuàng)造出更多的產(chǎn)出,相當于把自己的生命延長了。
其中有效的做法就是將每次活動進行拆分,自己執(zhí)行核心的【生命周期】,將【非核心生命周期】交給其它主體進行。
比如,用戶購物這一場景,從用戶進入到商店,進行瀏覽、詢問、購買等活動,到離開商店,都是按時間順序一步一步在執(zhí)行的。對于我們來說,這其中的每一步都需要時間,對于現(xiàn)代人來說,太奢侈了。如果這時候,我們把這個購物行為進行拆分,把選購交由別人執(zhí)行,由別人代替用戶上街選擇和過濾,或者通過網(wǎng)上推薦等來完成選購,用戶只需要最后確定物品的挑選即可。用戶的目的是買到自己需要的東西,而不是選購本身。這樣就可以大大節(jié)省用戶的時間,將更多的精力放到其他核心事情上。
再比如,現(xiàn)在吃飯,需要自己到菜市場買菜、回來煮飯煮菜,吃完飯后,還需要自己洗碗等。有時候完全可以叫外賣的,肚子餓了,點點【餓了嗎】,接著就可以繼續(xù)做自己的事情了,坐等外賣送到。將【煮飯】這一耗時的事情交給別人來做。
在編程語言中,這就是同步與異步的區(qū)別。異步的作用就是將耗時的事情交給【別人】來做,自己繼續(xù)進行;當【別人】做完事情后,執(zhí)行回調(diào)函數(shù),帶回結果,交回自己執(zhí)行。
回調(diào)函數(shù)雖然 Javascipt 語言是“單線程”執(zhí)行環(huán)境,但在執(zhí)行模式下,分成同步和異步兩種模式,其中我們更多的使用回調(diào)函數(shù)的方式來進行異步操作,如:
blogs.search = (words, res) => { const titleQuery = new AV.Query(Blog) titleQuery.contains("title", words); const descQuery = new AV.Query(Blog) descQuery.contains("desc", words); const tagsQuery = new AV.Query(Blog) tagsQuery.contains("tags", words); const wordsQuery = AV.Query.or(titleQuery, descQuery, tagsQuery); wordsQuery.descending("createdAt"); wordsQuery.limit(5); wordsQuery.find().then(function (results) { res(results); }, function (error) { res([]); }); }
這函數(shù)的作用就是通過關鍵詞words搜索,獲取滿足條件的公眾號文章,如果找不到就返回空數(shù)組。其中這里的res就是一個回調(diào)函數(shù)。在使用處:
server.route({ method: "POST", path: "/searchblog", handler: function (request, reply) { const words = request.payload.words; ModelBlog.search(words, results => { let data = []; results.forEach(function(v) { let wrap = {}; wrap.title = v.get("title"); wrap.description = v.get("desc"); wrap.picurl = v.get("picurl"); wrap.url = v.get("url"); data.push(wrap); }); reply(data); }); }, config: { validate: { payload: { words: Joi.string().required() } } } });
同樣的,在handler函數(shù)中的reply也是一個回調(diào)函數(shù),先通過ModelBlog.search函數(shù)內(nèi)嵌回調(diào)函數(shù)獲取數(shù)據(jù)庫中的文章數(shù)組,然后再對回調(diào)結果進行處理,返回給回調(diào)函數(shù)reply,最后返回給前端使用。
通過一個簡單的例子——“回調(diào)函數(shù),內(nèi)嵌回調(diào)函數(shù)”來說明回調(diào)函數(shù)是可以無窮盡的內(nèi)嵌,結果就是各個部分之間高度耦合,流程混在一起,每個任務只能指定一個回調(diào)函數(shù)。最終造成的結果就會嵌入回調(diào)地獄,很可能就像這樣了——結尾是無止境的});:
圖片來自于:
https://tutorialzine.com/media/2017/07/callback-hell.jpg
所謂 Promise, 就是一個對象,用來傳遞異步操作的消息。它代表了某個未來才會知道結果的事件 (通常是一個異步操作),并且這個事件提供統(tǒng)一的 API,可供進一步處理。
————來自《ES 6標準入門 (第二版)》
基于回調(diào)函數(shù)的異步處理如果統(tǒng)一參數(shù)使用規(guī)則的話,寫法也會很明了。但是,這也僅是編碼規(guī)范而已,即使采用不同的寫法也不會出錯。
而 Promise 則是把類似的異步處理對象和處理規(guī)則進行規(guī)范化,并按照采用統(tǒng)一的接口來編寫,而采用規(guī)定方法之外的寫法都會出錯。
除了 Promise 對象規(guī)定的方法 (這里的 then 或 catch )以外的方法都是不可以使用的,而不會像回調(diào)函數(shù)方式那樣可以自己自由的定義回調(diào)函數(shù)的參數(shù),而必須嚴格遵守固定、統(tǒng)一的編碼方式來編寫代碼。
這樣,基于 Promise 的統(tǒng)一接口的做法,就可以形成基于接口的各種各樣的異步處理模式。所以,Promise 的功能是可以將復雜的異步處理輕松的進行模式化,這也可以說是使用 Promise 的理由之一。
Promise 在規(guī)范上規(guī)定 Promise 只能使用異步調(diào)用方式。
如果將上面的 demo 重新用 Promise 來寫呢:
blogs.promise_search = (words) => { const promise = new Promise(function (resolve, reject) { const titleQuery = new AV.Query(Blog) titleQuery.contains("title", words); const descQuery = new AV.Query(Blog) descQuery.contains("desc", words); const tagsQuery = new AV.Query(Blog) tagsQuery.contains("tags", words); const wordsQuery = AV.Query.or(titleQuery, descQuery, tagsQuery); wordsQuery.descending("createdAt"); wordsQuery.limit(5); wordsQuery.find().then(function (results) { resolve(results); }, function (error) { reject(error); }); }); return promise; }
Promise 構造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)的兩個參數(shù)分別是 resolve 和 reject。它們是兩個函數(shù),由 Javascript 引擎提供,不用自己傳入。
其中,resolve 函數(shù)的作用是,將 Promise 對象的狀態(tài)從“未完成”變成“成功” (即從 Pending 變?yōu)?Resolved),在異步操作成功時調(diào)用,并將異步操作的結果作為參數(shù)傳遞出去;
reject 函數(shù)的作用是,將 Promise 對象的狀態(tài)從“未完成”變?yōu)椤笆 ?(即從 Pending 變?yōu)?Rejected),在異步操作失敗時調(diào)用,并將異步操作報出的錯誤作為參數(shù)傳遞出去。
Promise 實例執(zhí)行以后,可以用then方法分別指定Resolved狀態(tài)和Rejected狀態(tài)的回調(diào)函數(shù)。所以在使用處:
const words = request.payload.words; ModelBlog.promise_search(words).then(function (results) { let data = []; results.forEach(function(v) { let wrap = {}; wrap.title = v.get("title"); wrap.description = v.get("desc"); wrap.picurl = v.get("picurl"); wrap.url = v.get("url"); data.push(wrap); }); reply(data); }).catch(function (error) { reply([]); });
其中,then函數(shù)接受回調(diào)函數(shù),作為 Promise 對象的狀態(tài)變?yōu)?Resolved 時調(diào)用;而 catch 回調(diào)函數(shù)作為 Promise 對象的狀態(tài)變?yōu)?Rejected 時調(diào)用。和【異步函數(shù)】相比,簡單明了很多了,至少不用再傳遞回調(diào)函數(shù)到 ModelBlog 中,可以做到代碼的分離,ModelBlog 的作用只是為了拿到數(shù)據(jù),返回 Promise 對象,具體外界怎么使用,那是別人的事情了;同樣在使用方,可以直接調(diào)用 Promise 對象,通過 then 方法處理回調(diào)數(shù)據(jù)和錯誤信息,代碼也就更容易理解了。
但寫代碼總不能到處都是 Promise 對象,既然 Promise 能解決異步調(diào)用地獄的問題,但還有沒有更好的辦法將 Promise 異步方法寫的和同步寫法那樣,畢竟很多人已經(jīng)習慣面向過程的編寫方式了?
Async/AwaitAsync/Await是一個很久就令人期待的 JavaScript 功能,它讓使用異步函數(shù)更加愉快和容易理解。它是基于 Promise 的并且和現(xiàn)存的所有基于 Promise 的 API 相兼容。
從 async 和 await 這兩個名字來的這兩個關鍵字將會幫助我們整理我們的異步代碼。
async function getBlogsAsync(words) { const titleQuery = new AV.Query(Blog) titleQuery.contains("title", words); const descQuery = new AV.Query(Blog) descQuery.contains("desc", words); const tagsQuery = new AV.Query(Blog) tagsQuery.contains("tags", words); const wordsQuery = AV.Query.or(titleQuery, descQuery, tagsQuery); wordsQuery.descending("createdAt"); wordsQuery.limit(5); let results = await wordsQuery.find(); return results; }
這下連new Promise(...)都省了,直接寫核心業(yè)務代碼。很明顯 Async/Await 版本的代碼更短并且可讀性更強。除了使用的語法,兩個函數(shù)完全相同——他們都返回 Promise 并且都從數(shù)據(jù)庫得到 Blogs 數(shù)據(jù)返回。在使用時,還是和之前一樣,直接調(diào)用getBlogsAsync方法:
getBlogsAsync(words).then(function (results) { let data = []; results.forEach(function(v) { let wrap = {}; wrap.title = v.get("title"); wrap.description = v.get("desc"); wrap.picurl = v.get("picurl"); wrap.url = v.get("url"); data.push(wrap); }); reply(data); }).catch(function (error) { reply([]); });總結
隨著 Async/Await ,JavaScript語言在代碼可讀性和易用性上向前邁進了一大步。而且寫異步代碼,就跟常規(guī)的寫面向過程的同步代碼一樣,簡單直接明了。
最后分享幾個相關資料,值得一看,還有更多深入的內(nèi)容需要繼續(xù)挖掘:
Javascript異步編程的4種方法。http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html
《ES 6標準入門 (第二版)》,作者:阮一峰
JavaScript Async/Await Explained in 10 Minutes. https://tutorialzine.com/2017/07/javascript-async-await-explained
八段代碼徹底掌握 Promise. https://juejin.im/post/597724c26fb9a06bb75260e8
JavaScript Promise迷你書(中文版) http://liubin.org/promises-book/#promises-overview
理解 async/await. https://juejin.im/post/596e142d5188254b532ce2da
聽說最美的人和最帥的人,都會給作者打賞,以資鼓勵
coding01 期待您關注
文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/84604.html
摘要:想閱讀更多優(yōu)質(zhì)文章請猛戳博客一年百來篇優(yōu)質(zhì)文章等著你引入的在的異步編程中是一個極好的改進??赡軙a(chǎn)生誤導一些文章將與進行了比較,并聲稱它是下一代異步編程風格,對此作者深表異議。結論引入的關鍵字無疑是對異步編程的改進。 showImg(https://segmentfault.com/img/bVbjFP0?w=800&h=450); 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇...
摘要:事件循環(huán)從回調(diào)隊列中獲取并將其推入調(diào)用堆棧。執(zhí)行從調(diào)用堆棧中移除從調(diào)用堆棧中移除快速回顧值得注意的是,指定了事件循環(huán)應該如何工作,這意味著在技術上它屬于引擎的職責范圍,不再僅僅扮演宿主環(huán)境的角色。 此篇是 JavaScript是如何工作的第四篇,其它三篇可以看這里: JavaScript是如何工作的:引擎,運行時和調(diào)用堆棧的概述! JavaScript是如何工作的:深入V8引擎&編寫...
摘要:事件循環(huán)從回調(diào)隊列中獲取并將其推送到調(diào)用堆棧。如何工作請注意,不會自動將您的回調(diào)函數(shù)放到事件循環(huán)隊列中。它設置了一個計時器,當計時器到期時,環(huán)境將您的回調(diào)函數(shù)放入事件循環(huán)中,以便將來的某個事件會將其選中并執(zhí)行它。 我們將通過回顧第一篇文章中單線程編程的缺點,然后在討論如何克服它們來構建令人驚嘆的JavaScript UI。在文章結尾處,我們將分享5個關于如何使用async / awai...
摘要:函數(shù)會在之后的某個時刻觸發(fā)事件定時器。事件循環(huán)中的這樣一次遍歷被稱為一個。執(zhí)行完畢并出棧。當定時器過期,宿主環(huán)境會把回調(diào)函數(shù)添加至事件循環(huán)隊列中,然后,在未來的某個取出并執(zhí)行該事件。 原文請查閱這里,略有改動。 本系列持續(xù)更新中,Github 地址請查閱這里。 這是 JavaScript 工作原理的第四章。 現(xiàn)在,我們將會通過回顧單線程環(huán)境下編程的弊端及如何克服這些困難以創(chuàng)建令人驚嘆...
摘要:一方面,這里替代的是異步代碼的編寫方式,并非完全拋棄大家心愛的,地球人都知道是基于的,不用太傷心另一方面,是基于回調(diào)函數(shù)實現(xiàn)的,那也沒有替代回調(diào)函數(shù)咯重構代碼之后,我仍然用到了庫。 摘要: 夸張點說,技術的發(fā)展與歷史一樣,順之者昌,逆之者亡。JS開發(fā)者們,趕緊擁抱Async/Await吧! GitHub倉庫: Fundebug/promise-asyncawait 早在半年多之前,...
閱讀 2334·2021-11-24 09:39
閱讀 2566·2021-11-22 15:24
閱讀 3008·2021-09-02 09:48
閱讀 3058·2021-07-26 22:01
閱讀 1463·2019-08-30 11:09
閱讀 1706·2019-08-29 18:47
閱讀 635·2019-08-29 15:40
閱讀 2158·2019-08-29 15:22