电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

深入淺出 JS 異步處理技術方案

瀏覽:105日期:2024-05-26 16:33:15

為什么要異步

'當我們在星巴克買咖啡時,假設有100個人在排隊,也許咖啡的下單只要10S,但是咖啡的制作到客人領取咖啡要1000S。如果在同步的場景下,第一個客人下單到領取完咖啡要1010S才能輪到下一個客人,這在效率(某些場景)上來說會比較低下。如果我們異步處理這個流程,客人下單10S拿到憑證,客人就可以去做別的事情,并且10S后下一個客人可以繼續下單,并不阻礙流程。反而可以通過憑證,讓客人拿到自己的咖啡,也許時間上并不是第一個下單的客人先拿到。'

在網頁的世界里也是同樣的道理,不妨我們看看在執行JS代碼的主線程里,如果遇到了AJAX請求,用戶事件等,如果不采用異步的方案,你會一直等待,等待第一個耗時的處理完成才能接上下一個JS代碼的執行,于是界面就卡住了。

“也許有人會想,既然大家都說現在網頁上性能損耗最大的屬于DOM節點的操作,把這些搞成異步,行不行?其實這會帶來一個不確定性問題:既“成功”的狀態到底誰先來的問題??梢韵胂笠幌?,如果我們在操作DOM,既給節點添加內容,也給節點刪除,那么到底以誰為基準呢?考慮到復雜性,也就可見一斑了。”

Event loop

雖然異步與event loop沒有太直接的關系,準確的來講event loop 只是實現異步的一種機制。(了解為主)

“還是以上面咖啡館為例子,假定場景還是100人,這100人除了下單是與咖啡本身有關聯之外,其余的時間,比如看書,玩游戲的等可以視為自己的執行邏輯。如果用event loop來給它做一個簡單的畫像,那么它就像:在與咖啡店店員溝通下單視為主執行棧,咖啡的制作可以視為一個異步任務,添加到一個任務隊列里,一直等帶100個人都下單完成,然后開始讀取任務隊列中的異步任務,事件名就是下單憑證,如果有對應的handler,那么就執行叫對應的客人來領取咖啡。這個過程,是循環不斷的。假設沒有客人來下單的時候,也就是店員處于空閑時間(可能自己去搞點別的)?!?/p>

傳統的Callback

假定一個asyncFetchDataSource函數用于獲取遠程數據源,可能有20S。

function asyncFetchDataSource(cb){ (… 獲取數據, function(response){ typeof cb === ’function’ && cb(response) })}

這種形式的callback可以適用于簡單場景,如果這里有一個更復雜的場景,比如獲取完數據源之后,依據id,獲取到某個數據,在這某個數據中再依據id來更新某個列表,可以遇見的能看到代碼變成了:

asyncFetchDataSource(’’,function(data_a){ const { id_a } = data_a asyncFetchDataSource( id_a,function(data_b){ const { id_b } = data_b asyncFetchDataSource(id, function(data_c){ }) })})

如果有極端情況出現,這里的callback就會變成無極限了。

Thunk函數

這是一種“傳名調用”的策略,表現的形式就是將參數放入一個臨時函數,然后再將這個臨時函數傳入函數體內。

function asyncFetchDataSource(url){ return function(callback){ fetch(url, callback) }}const dataSource = asyncFetchDataSource(’https://github.com/icepy’);dataSource(function(data){})

Promise

Promise正是想來處理這樣的異步編程,如果我們用Promise該如何處理一段Ajax?

function fetch(){ return new Promise(function(resolve,reject){ $.ajax({ url: ’xxx’, success:function(data){resolve(data) }, error:function(error){reject(error) } }) })}fetch().then(function(data){}).catch(function(error){})

Promise聲明周期:

進行中(pending) 已經完成(fulfilled) 拒絕(rejected)

如同上面Ajax的例子,我們可以很好的包裝一個函數,讓fetch函數返回一個Promise對象。在Promise構造函數里,可以傳入一個callback,并且在這里完成主體邏輯的編寫。唯一需要注意的是:Promise對象只能通過resolve和reject函數來返回,在外部使用then或catch來獲取。如果你直接拋出一個錯誤(throw new Error(’error’)),catch也是可以正確的捕獲到的。

Promise其他的方法

Promise.all(當所有在可迭代參數中的 promises 已完成,或者第一個傳遞的 promise(指 reject)失敗時,返回 promise。)

var p1 = Promise.resolve(3);var p2 = 1337;var p3 = new Promise((resolve, reject) => { setTimeout(resolve, 100, 'foo');}); Promise.all([p1, p2, p3]).then(values => { console.log(values); // [3, 1337, 'foo'] });

Promise.race(返回一個新的 promise,參數iterable中只要有一個promise對象'完成(resolve)'或'失?。╮eject)',新的promise就會立刻'完成(resolve)'或者'失?。╮eject)',并獲得之前那個promise對象的返回值或者錯誤原因。)

var p1 = new Promise(function(resolve, reject) { setTimeout(resolve, 500, 'one'); });var p2 = new Promise(function(resolve, reject) { setTimeout(resolve, 100, 'two'); });Promise.race([p1, p2]).then(function(value) { console.log(value); // 'two' // 兩個都完成,但 p2 更快});

有趣的是如果你使用ES6的class,你是可以去派生Promise的。

class MePromise extends Promise{ // 處理 ...}

Generator

Generator可以輔助我們完成很多復雜的任務,而這些基礎知識,又與iterator息息相關,舉一個很簡單的例子,相信有很多朋友,應該使用過co這個異步編程的庫,它就是用Generator來實現,當然它的設計會比例子要復雜的多,我們先來看一個co簡單的用法:

import co from ’co’co(function* () { var result = yield Promise.resolve(true); return result;}).then(function (value) { console.log(value);}, function (err) { console.error(err.stack);});

相應的,我們來實現一個簡化的版本:

function co(task){ let _task = task() let resl = _task.next(); while(!resl.done){ console.log(resl); resl = _task.next(resl.value); }}function sayName(){ return { name: ’icepy’ }}function assign *(f){ console.log(f) let g = yield sayName() return Object.assign(g,{age:f});}co(function *(){ let info = yield *assign(18) console.log(info)})

雖然,這個例子中,還不能很好的看出來“異步”的場景,但是它很好的描述了Generator的使用方式。

從最開始的定義中,已經和大家說明了,Generator最終返回的依然是一個迭代器對象,有了這個迭代器對象,當你在處理某些場景時,你可以通過yield來控制,流程的走向。通過co函數,我們可以看出,先來執行next方法,然后通過一個while循環,來判斷done是否為true,如果為true則代表整個迭代過程的結束,于是,這里就可以退出循環了。在Generator中的返回值,可以通過給next方法傳遞參數的方式來實現,也就是遇上第一個yield的返回值。

有邏輯,自然會存在錯誤,在Generator捕獲錯誤的時機與執行throw方法的順序有關系,一個小例子:

let hu = function *(){ let g = yield 1; try { let j = yield 2; } catch(e){ console.log(e) } return 34}let _it = hu();console.log(_it.next())console.log(_it.next())console.log(_it.throw(new Error(’hu error’)))

當我能捕獲到錯誤的時機是允許完第二次的yield,這個時候就可以try了。

async await

async function createNewDoc() { let response = await db.post({}); // post a new doc return await db.get(response.id); // find by id}

https://tc39.github.io/ecmascript-asyncawait/

根據規范規定一個asnyc函數總是要返回一個Promise,從代碼直觀上來說,雖然簡潔了,但是async await并未萬能,它有很大的局限性,比如:

因為是順序執行,假設有三個請求,那么這里并沒有很好的利用到異步帶來的止損(再包裝一個Promise.all) 如果要捕獲異常,需要去包try catch 缺少控制流程,比如progress(進度)pause,resume等周期性的方法 沒有打斷的功能

主流的異步處理方案

我喜歡用co,而且社區使用也很廣泛, https://github.com/tj/co 。

co(function* () { var result = yield Promise.resolve(true); return result;}).then(function (value) { console.log(value);}, function (err) { console.error(err.stack);});

babel polyfill 支持,在瀏覽器環境中使用異步解決方案

如果你想使用全的polyfiil,直接npm install --save babel-polyfill,然后在webpack里進行配置即可。

module.exports = { entry: ['babel-polyfill', './app/js']};

當然由于我目前的開發基于的瀏覽器都比較高,所以我一般是挑選其中的:

https://github.com/facebook/regenerator/tree/master/packages/regenerator-runtime https://github.com/facebook/regenerator/tree/master/packages/regenerator-transform

如果你要使用async await 配置上 http://babeljs.io/docs/plugins/transform-async-to-generator/ 即可

Node.js 環境中使用異步解決方案

由于本人的node使用的LTS已經是8.9.3版本了,所以大部分情況下已經不再使用babel去進行轉換,而是直接使用co這樣的庫。當然co也不是萬能,一定要根據業務場景,與其他異步處理的方式,配合中使用。

總結 相信未來的JS編程,只會越來越簡單,不要拘泥于語法,語言上的特性,不妨多看一看“外面的世界“。

來自:http://www.iteye.com/news/32831

標簽: JavaScript
相關文章:
主站蜘蛛池模板: 刚性-柔性防水套管-橡胶伸缩接头-波纹管补偿器-启腾供水材料有限公司 | 户外健身路径_小区健身器材_室外健身器材厂家_价格-浩然体育 | 蔡司三坐标-影像测量机-3D扫描仪-蔡司显微镜-扫描电镜-工业CT-ZEISS授权代理商三本工业测量 | 反渗透水处理设备|工业零排放|水厂设备|软化水设备|海南净水设备--海南水处理设备厂家 | 企业VI设计_LOGO设计公司_品牌商标设计_【北京美研】 | 深圳市人通智能科技有限公司| sfp光模块,高速万兆光模块工厂-性价比更高的光纤模块制造商-武汉恒泰通 | 珠海网站建设_响应网站建设_珠海建站公司_珠海网站设计与制作_珠海网讯互联 | 丹佛斯变频器-丹佛斯压力开关-变送器-广州市风华机电设备有限公司 | 挖掘机挖斗和铲斗生产厂家选择徐州崛起机械制造有限公司 | 细胞染色-流式双标-试剂盒免费代做-上海研谨生物科技有限公司 | 水轮机密封网 | 水轮机密封产品研发生产厂家 | 东莞猎头公司_深圳猎头公司_广州猎头公司-广东万诚猎头提供企业中高端人才招聘服务 | 云南成考网_云南成人高考报名网 粤丰硕水性环氧地坪漆-防静电自流平厂家-环保地坪涂料代理 | 智成电子深圳tdk一级代理-提供TDK电容电感贴片蜂鸣器磁芯lambda电源代理经销,TDK代理商有哪些TDK一级代理商排名查询。-深圳tdk一级代理 | 济南玻璃安装_济南玻璃门_济南感应门_济南玻璃隔断_济南玻璃门维修_济南镜片安装_济南肯德基门_济南高隔间-济南凯轩鹏宇玻璃有限公司 | 密集架-密集柜厂家-智能档案密集架-自动选层柜订做-河北风顺金属制品有限公司 | 宿舍管理系统_智慧园区系统_房屋/房产管理系统_公寓管理系统 | 密集架-手摇-智能-移动-价格_内蒙古档案密集架生产厂家 | 农业仪器网 - 中国自动化农业仪器信息交流平台 | 武汉天安盾电子设备有限公司 - 安盾安检,武汉安检门,武汉安检机,武汉金属探测器,武汉测温安检门,武汉X光行李安检机,武汉防爆罐,武汉车底安全检查,武汉液体探测仪,武汉安检防爆设备 | 京港视通报道-质量走进大江南北-京港视通传媒[北京]有限公司 | 珠海白蚁防治_珠海灭鼠_珠海杀虫灭鼠_珠海灭蟑螂_珠海酒店消杀_珠海工厂杀虫灭鼠_立净虫控防治服务有限公司 | 一路商机网-品牌招商加盟优选平台-加盟店排行榜平台 | 存包柜厂家_电子存包柜_超市存包柜_超市电子存包柜_自动存包柜-洛阳中星 | 长沙印刷厂-包装印刷-画册印刷厂家-湖南省日大彩色印务有限公司 青州搬家公司电话_青州搬家公司哪家好「鸿喜」青州搬家 | 电子万能试验机_液压拉力试验机_冲击疲劳试验机_材料试验机厂家-济南众标仪器设备有限公司 | 亮化工程,亮化设计,城市亮化工程,亮化资质合作,长沙亮化照明,杰奥思【官网】 | 标策网-专注公司商业知识服务、助力企业发展 | 冷凝锅炉_燃气锅炉_工业燃气锅炉改造厂家-北京科诺锅炉 | 水篦子|雨篦子|镀锌格栅雨水篦子|不锈钢排水篦子|地下车库水箅子—安平县云航丝网制品厂 | 网站seo优化_seo云优化_搜索引擎seo_启新网络服务中心 | 工业胀紧套_万向节联轴器_链条-规格齐全-型号选购-非标订做-厂家批发价格-上海乙谛精密机械有限公司 | 衬塑管道_衬四氟管道厂家-淄博恒固化工设备有限公司 | POM塑料_PBT材料「进口」聚甲醛POM杜邦原料、加纤PBT塑料报价格找利隆塑料 | 焊锡丝|焊锡条|无铅锡条|无铅锡丝|无铅焊锡线|低温锡膏-深圳市川崎锡业科技有限公司 | crm客户关系管理系统,销售管理系统,crm系统,在线crm,移动crm系统 - 爱客crm | 厂房出售_厂房仓库出租_写字楼招租_土地出售-中苣招商网-中苣招商网 | 超声波焊接机,振动摩擦焊接机,激光塑料焊接机,超声波焊接模具工装-德召尼克(常州)焊接科技有限公司 | 武汉不干胶印刷_标签设计印刷_不干胶标签印刷厂 - 武汉不干胶标签印刷厂家 | 涡轮流量计_LWGY智能气体液体电池供电计量表-金湖凯铭仪表有限公司 |