日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

移动web app开发必备 - 异步队列 Deferred

發(fā)布時間:2024/9/20 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 移动web app开发必备 - 异步队列 Deferred 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

背景

移動web app開發(fā),異步代碼是時常的事,比如有常見的異步操作:

  • Ajax(XMLHttpRequest)
  • Image Tag,Script Tag,iframe(原理類似)
  • setTimeout/setInterval
  • CSS3 Transition/Animation
  • HTML5 Web Database
  • postMessage
  • Web Workers
  • Web Sockets
  • and more…

后面幾個是CSS3 HML5加入的新API.這些接口都是會產(chǎn)生異步的操作

比如本人的一個phonegap項目,操作HTML5本地數(shù)據(jù)庫(HTML5 Web Database)就是一個異步的過程,如果同時執(zhí)行多個查詢,勢必同步代碼要等待數(shù)據(jù)查詢結(jié)束后調(diào)用

附項目源碼:執(zhí)行多次異步查詢

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 /** ??* 初始化操作 ??* @return ??*/ ?proto.initProcess =?function(){ ?????var?self =?this, ?????????prev =?null?, ?????????curr =?null?, ?????????next =?null?; ?????debug.group("start of init process"); ?????var?idx = self.chapterIndex; ?????debug.info("PageBase: 執(zhí)行初始化之前的操作!"); ?????self.initProcessBefore(); ?????if(idx == 0){ ?????????debug.info("PageBase: 初始化入口點(diǎn)從第一章開始進(jìn)入"); ?????????debug.info("PageBase: 解析器解析第一章數(shù)據(jù)!"); ?????????curr = self.process(self.chapters[idx]); ?????????curr.then(function(pages){ ?????????????debug.info(self.format("PageBase: 第一章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?, pages.length)); ?????????????self.cPages = pages; ?????????????if(self.isChangeFont){ ???????????????self.idx = Math.ceil((pages.length - 1) * self.idx);????????????????? ?????????????} ?????????????self.cPages.idx = idx; ?????????????/ ?????????????// ?????????????// 2013.1.10修改 ?????????????//?? 如果只有一個章節(jié)的情況下 ?????????????// ?????????????if(1 === self.chapters.length){ ???????????????deferred.all([curr]).then(self.steup.bind(self));?? ?????????????}else{ ???????????????debug.info("PageBase:解析器解析后一章數(shù)據(jù)!"); ???????????????next = self.loadNextData(idx + 1); ???????????????next.then(function(args){ ???????????????????debug.info(self.format("PageBase: 后一章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?, args.pages.length)); ???????????????????self.nPages = args.pages; ???????????????????self.nPages.idx = idx + args.index; ???????????????????debug.info(self.format("PageBase: 初始化數(shù)據(jù)解析完成, 當(dāng)章索引{0} 當(dāng)章頁數(shù){1} 下章索引{2}? 下章頁數(shù){3}" ???????????????????????????, self.cPages.idx , self.cPages.length , self.nPages.idx , self.nPages.length)); ???????????????????debug.info("PageBase: 初始化數(shù)據(jù)解析完成,即將生成結(jié)構(gòu)操作!"); ???????????????}); ???????????????deferred.all([curr , next]).then(self.steup.bind(self));?? ?????????????} ?????????}); ?????}else?if(idx == self.chapters.length -1){ ?????????debug.info("PageBase: 初始化入口點(diǎn)從最后一章開始進(jìn)入"); ?????????debug.info("PageBase:解析器解析最后一章數(shù)據(jù)!"); ?????????prev = self.loadPrevData(idx - 1); ?????????prev.then(function(args){ ?????????????self.pPages = args.pages; ?????????????self.pPages.idx = args.index + 1; ?????????????debug.info(self.format("PageBase: 最后一章的前一章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?, args.pages.length)); ?????????????curr = self.process(self.chapters[idx]); ?????????????curr.then(function(pages , data){ ?????????????????if(self.isChangeFont){ ???????????????????self.idx = Math.ceil((pages.length - 1) * self.idx);????????????????? ?????????????????} ?????????????????self.cPages = pages ; ?????????????????self.cPages.idx = idx; ?????????????????debug.info(self.format("PageBase: 最后一章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?, pages.length)); ?????????????????debug.info(self.format("PageBase: 初始化數(shù)據(jù)解析完成, 前章索引{0} 前章頁數(shù){1} 當(dāng)章索引{2} 當(dāng)章頁數(shù){3} " ?????????????????????????, self.pPages.idx , self.pPages.length , self.cPages.idx , self.cPages.length )); ?????????????????debug.info("PageBase: 初始化數(shù)據(jù)解析完成,即將生成結(jié)構(gòu)操作!"); ?????????????}); ?????????????deferred.all([prev , curr]).then(self.steup.bind(self)); ?????????}); ?????}else{ ?????????debug.info("PageBase: 初始化入口點(diǎn)從中間章開始進(jìn)入"); ?????????prev = self.loadPrevData(idx - 1); ?????????debug.info("PageBase:解析器解析中間章的前一章數(shù)據(jù)!"); ?????????prev.then(function(args){ ?????????????self.pPages = args.pages ; ?????????????self.pPages.idx = args.index; ?????????????debug.info(self.format("PageBase: 中間章前一章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?, args.pages.length)); ?????????????debug.info("PageBase:解析器解析中間章數(shù)據(jù)!"); ?????????????curr = self.process(self.chapters[idx]); ?????????????curr.then(function(pages , data){ ?????????????????if(self.isChangeFont){ ?????????????????????self.idx = Math.ceil((pages.length) * self.idx); ?????????????????????// console.log("spages.length - 1",pages.length)????? ?????????????????????// console.log("self.idx",self.idx)???????????? ?????????????????} ?????????????????self.cPages = pages ; ?????????????????self.cPages.idx = idx; ?????????????????debug.info(self.format("PageBase: 中間章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?,pages.length)); ?????????????????debug.info("PageBase:解析器解析中間章的后一章數(shù)據(jù)!"); ?????????????????next = self.loadNextData(idx + 1); ?????????????????next.then(function(args){ ?????????????????????self.nPages = args.pages ; ?????????????????????self.nPages.idx = idx + args.index; ?????????????????????debug.info(self.format("PageBase: 中間章后一章數(shù)據(jù)解析完成,解析頁面數(shù)為{0}"?, args.pages.length)); ?????????????????????debug.info(self.format("PageBase: 初始化數(shù)據(jù)解析完成, 前章索引{0} 前章頁數(shù){1} 當(dāng)章索引{2} 當(dāng)章頁數(shù){3} 下章索引{4}? 下章頁數(shù){5}" ?????????????????????????, self.pPages.idx , self.pPages.length , self.cPages.idx , self.cPages.length , self.nPages.idx , self.nPages.length)); ?????????????????????debug.info("PageBase: 初始化數(shù)據(jù)解析完成,即將生成結(jié)構(gòu)操作!") ?????????????????}); ?????????????????deferred.all([prev , curr , next]).then(self.steup.bind(self));? ?????????????}); ?????????}); ????}

如何組織代碼

但是對于異步+回調(diào)的模式,當(dāng)需要對一系列異步操作進(jìn)行流程控制的時候似乎必然會面臨著回調(diào)嵌套。因此怎么把異步操作“拉平”,用更好的方法去優(yōu)化異步編程的體驗,同時也寫出更健壯的異步代碼,是這兩年來前端圈子里很火的話題。

代表的

  • 消息驅(qū)動——代表:@樸靈?的EventProxy
  • Promise模式——代表:CommonJS Promises,jQuery,Dojo?
  • 二次編譯——代表:@老趙?的Jscex
  • jQuery 是唯一的實(shí)現(xiàn)了這種 when 方法的庫。其他的 promises 庫,例如??Q,?Dojo, 和??when?依照??Promises/B spec?實(shí)現(xiàn)了 when 方法, 但是并沒有實(shí)現(xiàn)注釋者提及的 when 方法。但是,Q 庫有一個???all方法,when.js 也有一個??parallel方法,與上面的 jQuery.when 方法作用一樣,只是它們接受一個數(shù)組類型的參數(shù),而不是任意數(shù)量的參數(shù)。
  • ?回顧Jquery?Deferred

    • 從1.5版本開始,jQuery加入了Deferred功能,讓事件處理隊列更加的完善。并用 這個機(jī)制重寫了Ajax模塊。雖然還沒輪到Ajax,但是接下來的事件處理函數(shù)中牽扯到了 這個機(jī)制
    • Deferred把回調(diào)函數(shù)注冊到一個隊列中,統(tǒng)一管理,并且可以同步或者異步地調(diào)用 這些函數(shù)。jQuery.Deferred()用來構(gòu)造一個Deferred對象。該對象有狀態(tài)值,共有三種: Rejected, Resolved和初始狀態(tài)。其中Resolved表示該操作成功完成了,而Rejected 則表示出現(xiàn)了錯誤,調(diào)用失敗。Deferred對象的主要成員如下:
    • done(callback): 注冊一個callback函數(shù),當(dāng)狀態(tài)為resolved時被調(diào)用。
    • fail(callback): 注冊一個callback函數(shù),當(dāng)狀態(tài)為rejected時被調(diào)用。
    • always(callback): 注冊一個callback函數(shù),無論是resolved或者rejected都會被 調(diào)用。
    • then(successCallback, failureCallback): 同時傳入成功和失敗的回調(diào)函數(shù)。
    • pipe(successFilter, failureFilter): 在調(diào)用成功和失敗的回調(diào)函數(shù)前先調(diào)用pipe 指定的函數(shù)。算是一種管道機(jī)制,攔截了函數(shù)調(diào)用。
    • resolve(args): 把狀態(tài)設(shè)置為Resolved。
    • reject(args): 把狀態(tài)設(shè)置為Rejected。
    • promse(): 返回的是一個不完整的Deferred的接口,沒有resolve和reject。即不能 修改Deferred對象的狀態(tài)。可以看作是一種只讀視圖。這是為了不讓外部函數(shù)提早觸發(fā) 回調(diào)函數(shù)。比如$.ajax在1.5版本后不再返回XMLHttpRequest,而是返回一個封裝了 XMLHttpRequest和Deferred對象接口的object。其中Deferred部分就是promise()得到 的,這樣不讓外部函數(shù)調(diào)用resolve和reject,防止在ajax完成前觸發(fā)回調(diào)函數(shù)。把這 兩個函數(shù)的調(diào)用權(quán)限保留給ajax內(nèi)部。

    ?deferred-js

    本人在項目中使用 Promise/A 規(guī)范實(shí)現(xiàn)的?deferred-js?, 比較簡單輕巧.

    如何使用?

    API:

    var?DeferredAPI = { ????deferred???? : deferred, ????all????????? : all, ????Deferred???? : Deferred, ????DeferredList : DeferredList, ????wrapResult?? : wrapResult, ????wrapFailure? : wrapFailure, ????Failure????? : Failure }

    最簡單常用的案例

    //Deferred對象創(chuàng)建var d = new deferred.Deferred()//添加一個回調(diào)到遞延的回調(diào)鏈d.then(function(result) {console.log('Hello ' + result)return result})//等待回調(diào)后觸發(fā)d.resolve('World')

    每個鏈接在一個回調(diào)鏈可以是兩個函數(shù),代表一個成功,一個失敗

    只有一個成功回調(diào)

    d.then(function(result) {// 自己的代碼return result })

    失敗回調(diào)

    d.fail(function(failure) {// optionally do something useful with failure.value()return failure });

    添加一個成功方法和一個失敗方法

    d.then(function(result) {// do something useful with the resultreturn result }, function(failure) {// optionally do something useful with failure.value()return failure })

    不管回調(diào)成功或者失敗都執(zhí)行同一份代碼

    d.both(function(result) {// in the case of failure, result is a Failure// do something in either casereturn result })

    如果許多異步在操作,比如提供的案例,在要執(zhí)行HTML5數(shù)據(jù)庫N次后,如何操作呢?

    ?請仔細(xì)對照下案例中的

    deferred.all([prev , curr , next]).then(self.steup.bind(self));

    all的方法等待所有的延時隊列加載完畢后,才執(zhí)行后續(xù)代碼

    使用起來很方便,很精簡沒有那么多復(fù)雜的概念

    使用教程之后,下一節(jié)附源碼的實(shí)現(xiàn)

    總結(jié)

    以上是生活随笔為你收集整理的移动web app开发必备 - 异步队列 Deferred的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。