Ember.js 入門指南——非同步路由
本文將為你介紹路由的高階特性,這些高階特性可以用於處理專案複雜的非同步邏輯。
關於單詞promises,直譯是承諾,但是個人覺得還是使用原文吧。讀起來順暢點。
1,promises(承諾)
Ember的路由處理非同步邏輯的方式是使用promises。簡而言之,promises就是一個表示最終結果的物件。這個物件可能是fulfill(成功獲取最終結果)也可能是reject(獲取結果失敗)。為了獲取這個最終值,或者是處理promises失敗的情況都可以使用then方法,這個方法接受兩個可選的回撥方法,一個是promises獲取結果成功時執行,一個是promises獲取結果失敗時執行。如果
// app/routes/promises.js import Ember from 'ember'; export default Ember.Route.extend({ beforeModel: function() { console.log('execute model()'); var promise = this.fetchTheAnswer(); promise.then(this.fulfill, this.reject); }, // promises獲取結果成功時執行 fulfill: function(answer) { console.log("The answer is " + answer); }, // promises獲取結果失敗時執行 reject: function(reason) { console.log("Couldn't get the answer! Reason: " + reason); }, fetchTheAnswer: function() { return new Promise(function(fulfill, reject){ return fulfill('success'); //如果返回的是fulfill則表示promises執行成功 //return reject('failure'); //如果返回的是reject則表示promises執行失敗 }); } });
上述這段程式碼就是promises的一個簡單例子,promises的then方法會根據promises的獲取到的最終結果執行不同的回撥,如果promises獲取結果成功則執行fulfill回撥,否則執行reject回撥。
promises的強大之處不僅僅如此,promises還可以以鏈的形式執行多個then方法,每個then方法都會根據promises的結果執行fulfill或者reject回撥。
// app/routes/promises.js import Ember from 'ember'; export default Ember.Route.extend({ beforeModel() { // 注意Jquery的Ajax方法返回的也是promises var promiese = Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls'); promiese.then(this.fetchPhotoOfUsers) .then(this.applyInstagramFilters) .then(this.uploadThrendyPhotAlbum) .then(this.displaySuccessMessage, this.handleErrors); }, fetchPhotoOfUsers: function(){ console.log('fetchPhotoOfUsers'); }, applyInstagramFilters: function() { console.log('applyInstagramFilters'); }, uploadThrendyPhotAlbum: function() { console.log('uploadThrendyPhotAlbum'); }, displaySuccessMessage: function() { console.log('displaySuccessMessage'); }, handleErrors: function() { console.log('handleErrors'); } });
這種情況下會列印什麼結果呢??
在前的文章已經使用過Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');獲取資料,是可以成功獲取資料的。所以promises獲取結果成功,應該執行的是獲取成功對應的回撥方法。瀏覽器控制檯列印結果如下:
fetchPhotoOfUsers applyInstagramFilters uploadThrendyPhotAlbum displaySuccessMessage
但是如果我把Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');改成一個不存在的URL,比如改成Ember.$.getJSON('https://www.my-example.com');執行程式碼之後控制檯會提示出404錯誤,並且列印'handleErrors'。說明promises獲取結果失敗,執行了then裡的reject回撥。為了驗證每個回撥的reject方法再修改修改程式碼,如下:
// app/routes/promises.js import Ember from 'ember'; export default Ember.Route.extend({ beforeModel() { // 注意Jquery的Ajax方法返回的也是promises var promiese = Ember.$.getJSON(' https://www.my-example.com '); promiese.then(this.fetchPhotoOfUsers, this.fetchPhotoOfUsersError) .then(this.applyInstagramFilters, this.applyInstagramFiltersError) .then(this.uploadThrendyPhotAlbum, this.uploadThrendyPhotAlbumError) .then(this.displaySuccessMessage, this.handleErrors); }, fetchPhotoOfUsers: function(){ console.log('fetchPhotoOfUsers'); }, fetchPhotoOfUsersError: function() { console.log('fetchPhotoOfUsersError'); }, applyInstagramFilters: function() { console.log('applyInstagramFilters'); }, applyInstagramFiltersError: function() { console.log('applyInstagramFiltersError'); }, uploadThrendyPhotAlbum: function() { console.log('uploadThrendyPhotAlbum'); }, uploadThrendyPhotAlbumError: function() { console.log('uploadThrendyPhotAlbumError'); }, displaySuccessMessage: function() { console.log('displaySuccessMessage'); }, handleErrors: function() { console.log('handleErrors'); } });
由於promises獲取結果失敗故執行其對應的失敗處理回撥。這種呼叫方式有點類似於try……catch……,但是本文的重點不是講解promises,更多有關promises的教材請讀者自行Google或者百度吧,在這裡介紹一個js庫,它可以讓你更加簡單的組織你的promises程式碼。
在附上幾個promises的參考網站:
極力推薦看第二個網站的教材,這個網站可以直接執行js代碼。還有源碼和PDF。非常棒!!!
2,promises中止路由
當發生路由切換的時候,在model回撥(或者是beforeMode、afterModel)中獲取的資料集會在切換完成的時候傳遞到路由對應的controller上。如果model回撥返回的是一個普通的物件(非promises物件)或者是陣列,路由的切換會立即執行,但是如果model回撥返回的是一個promises物件,路由的切換將會被中止直到promises執行完成(返回fulfill或者是reject)才切換。
路由器任務任何一個包含了then方法的物件都是一個promises。
如果promises獲取結果成功則會從被中止的地方繼續往下執行或者是執行路由鏈的下一個路由,如果promises返回的依然是一個promises,那麼路由依然再次被中止,等待promises的返回結果,如果是fulfill則從被中止的地方開始往下執行,以此類推,一直到獲取到model回撥所需的結果。
傳遞到每個路由的setupController回撥的值都是promises返回fulfill時的值。如下程式碼:
// app/routes/tardy.js import Ember from 'ember'; export default Ember.Route.extend({ model: function() { return new Ember.RSVP.Promise(function(resolver) { console.log('start......'); Ember.run.later(function() { resolver({ msg: 'Hold your horses!!'}); }, 3000); }); }, setupController(controller, model) { console.log('msg = ' + model.msg); } });
一進入路由tardy,model回撥就會被執行並且返回一個延遲3秒才執行的promises,在這期間路由會中止。當promises返回fulfill路由會繼續執行,並將model返回的物件傳遞到setupController方法中。
雖然這種中止的行為會影響響應速度但是這是非常必要的,特別是你需要保證model回撥得到的資料是完整的資料的時候。
3,promises獲取結果失敗
文章前面主要講的是promises獲取結果成功的情況,但是如果是獲取結果失敗的情況又是怎麼處理呢??
預設情況下,如果model回撥返回的是一個promises物件並且此promises返回的是reject,此時路由切換將被終止,也不會渲染對應的模板,並且會在瀏覽器控制檯打印出錯誤日誌資訊,例子promises-ret-reject.js會演示。
你可以自定義處理出錯資訊的邏輯,只要在route的actions雜湊物件中配置即可。當promises獲取結果失敗的預設情況下會執行一個名為error的處理事件,否則會執行你自定義的處理事件。
// app/routes/promises-ret-reject.js import Ember from 'ember'; export default Ember.Route.extend({ model: function() { // 為了測試效果直接返回reject return Ember.RSVP.reject('FAIL'); }, actions: { error: function(reason) { console.log('reason = ' + reason); // 如果你想讓這個事件冒泡到頂級路由application只需要返回true // return true; } } });
如果沒有不允許事件冒泡列印結果僅僅是“reason = FAIL”。並且頁面上什麼都不顯示(不渲染模板)。
如果去掉最後一行程式碼的註釋,讓事件冒泡到頂級路由application中的預設方法處理,那麼結果又是什麼呢?
結果是先列印了處理結果,然後再打印出提示錯誤的日誌資訊。並且頁面上什麼都不顯示(不渲染模板)。
4,恢復promises的reject狀態
在前面第3點介紹了promises獲取結果失敗時會終止路由切換,但是如果model返回是一個promises鏈呢?程式能到就這樣死了!!!顯然是不行的,做法是把model回撥中返回的reject轉換為fulfill。這樣就可以繼續執行或者切換到下一個路由了!
// app/routes/funky.js import Ember from 'ember'; export default Ember.Route.extend({ model: function() { var promises = Ember.RSVP.reject('FAIL'); // 由於已經知道promises返回的是reject,所以fulfill回撥直接寫為null return promises.then(null, function() { return { msg: '恢復reject狀態:其實就是在reject回撥中繼續執行fulfill狀態下的程式碼。' }; }); } });
為了驗證model回撥的結果,直接在模板上顯示msg。
<!-- app/templates/funky.hbs -->
funky模板
<br>
{{model.msg}}
說明model回撥進入到reject回撥中,並正確返回了預期結果。
到本文為止有關路由這以整章的內容也全部介紹完畢了!!難點在《Ember.js 入門指南——查詢引數》這一篇。能力有限沒有把這篇的內容講明白,暫時擱下待日後完善!
總的來說路由主要職責是獲取資料,根據邏輯處理資料。有點MVC架構的dao層,專門做資料的CRUD操作。當然另外一個重要職責就是路由的切換,以及切換的時候引數的設定問題。
結束完這一章下一章接著介紹元件(Component),正好是國慶休息幾天再繼續吧!!祝大夥國慶快樂!!!
相關推薦
Ember.js 入門指南——非同步路由
本文將為你介紹路由的高階特性,這些高階特性可以用於處理專案複雜的非同步邏輯。 關於單詞promises,直譯是承諾,但是個人覺得還是使用原文吧。讀起來順暢點。 1,promises(承諾) Ember的路由處理非同步邏輯的方式是使用promises。簡
Ember.js 入門指南——路由定義
當你的應用啟動的時候,路由器就會匹配當前的URL到你定義的路由上。然後按照定義的路由層次逐個載入資料、設定應用程式狀態、渲染路由對應的模板。 1,基本路由 在app/router.js的map方法裡定義的路由會對映到當前的URL。當map方法被
Ember.js 入門指南——路由切換的防止和重試
在路由的切換過程中,Ember路由器會通過回撥(beforeModel、model、afterModel、redirect)解析一個transition物件到切換的下一路由中。任何一個回撥都可以通過傳遞過來的transition引數獲取transition物件,然
Ember.js 入門指南 (二)
@(Ember)[MVVM|前端框架|HTML桌面應用] 序言 經常有人質疑,在前端搞MV*有什麼意義?也有人跟我提出這樣的疑問:以AngularJS,Knockout,BackBone為代表的MV*框架,它跟jQuery有什麼區別?我jQuery用
Ember.js 入門指南——處理事件
ber.js 入門指南——處理事件 你可以在元件中響應事件,比如使用者的雙擊、滑鼠滑過、鍵盤的按下等等事件。只需要在元件類中增加Ember提供的處理事件,然後Ember會自動判斷使用者的操作執行相應的事件,只要在元件類中新增的事件不衝突你甚至一次性增加多個
Ember.js 入門指南——控制器(controller)
ember new chapter5_controllers cd chapter5_controllers ember server 從本篇開始進入第五章控制器,controller在Ember2.0開始越來越精簡了,職責也更加單一——處理邏輯。 下面是準備工作。
Ember.js 入門指南——元件定義
不得不說,Ember的更新是在是太快了!!本教程還沒寫到一半就又更新到v2.1.0了!!!!不過為了統一還是使用官方v2.0.0的參考文件!! 從本篇開始進入新的一章——元件。這一章將用6篇文章介紹Ember的元件,從它的定義開始知道它的使用方式,
Ember.js 入門指南——新建、更新、刪除記錄
前一篇介紹了查詢方法,本篇介紹新建、更新、刪除記錄的方法。 本篇的示例程式碼建立在上一篇的基礎上。對於整合firebase、建立route和template請參看上一篇,增加一個controller:ember g controller articles。 1,新建
Ember.js 入門指南——{{action}} 助手
action助手所現實的功能與javascript裡的事件是相似的,都是通過使用者點選元素觸發定義在元素上的事件。Ember的action助手還允許你傳遞引數到對應的controller、component類,在controller或者component上處理事件的邏輯。
Ember.js 入門指南——工具類的助手
本篇主要介紹格式轉換、自定義helper、自定義helper引數、狀態helper、HTML標籤轉義這幾個方面的東西。 按照文章慣例先準備好測試所需要的資料、檔案。仍然是使用Ember CLI命令,這次我們建立的是helper、controller、route
Ember.js 入門指南——繫結(bingding)
正如其他的框架一樣Ember也包含了多種方式繫結實現,並且可以在任何一個物件上使用繫結。也就是說,繫結大多數情況都是使用在Ember框架本身,對於開發最好還是使用計算屬性。 1,雙向繫結 // 雙向繫結 Wife = Ember.Object.extend(
Ember.js 入門指南——表單元素
Ember提供的表單元素都是經過封裝的,封裝成了view元件。經過解析渲染之後就會生成普通的HTML標籤。更多詳細資訊你可以檢視他們的實現原始碼:Ember.TextField、Ember.Chechbox、Ember.TextArea。 按照慣例,先建
Ember.js 入門指南——{{link-to}} 助手
1,link-to助手常規使用 link-to助手錶達式渲染之後就是一個a標籤。而a標籤的href屬性的值是根據路由生成的,與路由的設定是息息相關的。並且每個設定的路由名稱都是有著對應的關係的。 為了演示效果,用命令生成了一個route(或者手動建立檔案)並獲取測試資
易學筆記-第2部分 Node.js入門指南/第5章 Node.js在幣圈流行麼
第2部分 Node.js入門指南/第5章 Node.js在幣圈流行麼/5.1 Node.js在開源社群很流行 Node.js在開源社群很流行 概念:JavaScript大部分專案都是建立在Node.js平臺之上的 在Github上專案採用的語言統計,JavaScr
three.js 入門指南(敷衍一下)
今天看了一本好書three.js,感覺特別適合我這種對three.js 瞭解不深的人。 其實要學習three.js,還有許多其他方面的知識要了解,例如如何繪製多邊形,如何繪製曲線,攝像機的一些基礎知識等等。 推薦一本老外的three.js指南 https://pan.baidu.com/
Node.js入門:非同步IO
非同步IO 在作業系統中,程式執行的空間分為核心空間和使用者空間。我們常常提起的非同步I/O,其實質是使用者空間中的程式不用依賴核心空間中的I/O操作實際完成,即可進行後續任務。 同步IO的並行模式 多執行緒單程序 多執行緒的設計之處就是為了在共享的程式空間中,實現並行處理
node js 入門指南
-type ctu tor tex UNC erp func ons 消息 一旦你已經安裝了 Node,讓我們嘗試構建第一個 Web 服務器。 請創建一個“app.js”文件,黏貼以下代碼: const http = require(‘http‘)
Vue.js新手入門指南
最近在逛各大網站,論壇,以及像SegmentFault等程式設計問答社群,發現Vue.js異常火爆,重複性的提問和內容也很多,樓主自己也趁著這個大前端的熱潮,著手學習了一段時間的Vue.js,目前用它正在做自己的結業專案。 在做的過程中也對Vue.js的官方文件以及其各種特性有了許多認識。作為一個之
pdf.js 入門使用指南4-手機端瀏覽pdf(touch.js)
經過測試,使用pdf.js這個開源庫,自己編寫程式碼實現pdf 檔案瀏覽也不是很複雜。參照我以前的blog文章,如果要實現上一頁,下一頁,旋轉等都非常簡單。 但是,手機端是個比較依賴手勢特殊存在。如果要實現如下功能: 1:雙指放大,通過捏合雙指進行放大或縮小 2:單個手指
pdf.js 入門使用指南3-字型顯示問題
1:亂碼問題。最近遇到一個問題,一個pdf 檔案使用了冷門的字型,導致出現亂碼,字型空白,如下圖所示 2:問題排查,初步排查,治標。 修改改pdf 檔案,把字型都修改成宋體。再次預覽,顯示正常 。 3:從問題上根治這個問