javascript語(yǔ)言,皮毛好學(xué),容易上手,但真正深入學(xué)習(xí)的話(huà),確實(shí)像好多人說(shuō)的那樣,比較難。JavaScript語(yǔ)言,零散,不像java那樣系統(tǒng),而且編寫(xiě)調(diào)試JavaScript語(yǔ)言比較麻煩,不像java那樣直接有編寫(xiě)錯(cuò)誤提示。種種方面結(jié)合起來(lái),JavaScript語(yǔ)言就比較難學(xué),難掌控,而且涉及到瀏覽器兼容問(wèn)題,也是一大難點(diǎn),比如有的命令在Firefox上可以出來(lái)效果,但在IE上就報(bào)錯(cuò)了。要是像某些人說(shuō),一周學(xué)會(huì)的話(huà),有點(diǎn)兒可笑了,真正的天才都達(dá)不到幾天學(xué)會(huì)的。最多最多這幾天,了解了下JavaScript語(yǔ)言的基礎(chǔ)皮毛而已。
站在用戶(hù)的角度思考問(wèn)題,與客戶(hù)深入溝通,找到進(jìn)賢網(wǎng)站設(shè)計(jì)與進(jìn)賢網(wǎng)站推廣的解決方案,憑借多年的經(jīng)驗(yàn),讓設(shè)計(jì)與互聯(lián)網(wǎng)技術(shù)結(jié)合,創(chuàng)造個(gè)性化、用戶(hù)體驗(yàn)好的作品,建站類(lèi)型包括:網(wǎng)站制作、網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣、域名與空間、虛擬主機(jī)、企業(yè)郵箱。業(yè)務(wù)覆蓋進(jìn)賢地區(qū)。
學(xué)軟件開(kāi)發(fā)需要的基礎(chǔ)知識(shí)有:1、數(shù)學(xué)和英語(yǔ)基礎(chǔ)知識(shí);2、基礎(chǔ)編程語(yǔ)言;3、數(shù)據(jù)庫(kù)知識(shí);4、web相關(guān)知識(shí)。軟件開(kāi)發(fā)是根據(jù)用戶(hù)要求建造出軟件系統(tǒng)或者系統(tǒng)中的。1.
基礎(chǔ)知識(shí) 學(xué)軟件開(kāi)發(fā)往往要與數(shù)學(xué)和英文打交道,所以要有一定的數(shù)學(xué)、 英語(yǔ)基礎(chǔ),有一定的基礎(chǔ)在學(xué)習(xí)軟件開(kāi)發(fā)上可以說(shuō)是事半功倍了。如 果英語(yǔ)、數(shù)學(xué)不錯(cuò)的,可以跳過(guò)這一步。
2.
基礎(chǔ)編程語(yǔ)言知識(shí) 北大青鳥(niǎo)佳音校區(qū)的資深軟件開(kāi)發(fā)老師指出, 實(shí)現(xiàn)軟件運(yùn)行都由 某種程序語(yǔ)言來(lái)實(shí)現(xiàn), 所以學(xué)好程序語(yǔ)言是做好軟件開(kāi)發(fā)工作的必修 課。
最難的是函數(shù)是對(duì)象,函數(shù)又不僅僅是對(duì)象,還可以做面向?qū)ο笾械念?lèi)使用。
數(shù)組可以是對(duì)象集合,數(shù)組也可以是函數(shù)集合。
對(duì)象變化又過(guò)于靈活。所以要想深入學(xué)習(xí),不在于語(yǔ)法,學(xué)會(huì)語(yǔ)法之后更需多加練習(xí)多加體會(huì)。
從 基本的對(duì)象方法、事件、屬性
到 函數(shù)調(diào)用 匿名函數(shù)
到 JSON
到 函數(shù)套用 匿名函數(shù)套用 閉包
到 prototype
需要不斷地學(xué)習(xí)和體會(huì)。
軟件開(kāi)發(fā)是根據(jù)用戶(hù)要求,建造出軟件系統(tǒng)或者系統(tǒng)中的軟件部分的過(guò)程。 軟件開(kāi)發(fā)是一項(xiàng)包括需求捕捉,需求分析,設(shè)計(jì),實(shí)現(xiàn)和測(cè)試的系統(tǒng)工程。
軟件一般是用某種程序設(shè)計(jì)語(yǔ)言來(lái)實(shí)現(xiàn)的。 通常采用軟件開(kāi)發(fā)工具可以進(jìn)行開(kāi)發(fā)。 軟件分為系統(tǒng)軟件和應(yīng)用軟件。 軟件并不只是包括可以在計(jì)算機(jī)上運(yùn)行的程序,與這些程序相關(guān)的文件一般也被認(rèn)為是軟件的一部分。 軟件設(shè)計(jì)思路和方法的一般過(guò)程,包括設(shè)計(jì)軟件的功能和實(shí)現(xiàn)的算法和方法、軟件的總體結(jié)構(gòu)設(shè)計(jì)和模塊設(shè)計(jì)、編程和調(diào)試、程序聯(lián)調(diào)和測(cè)試以及編寫(xiě)、提交程序。
一般來(lái)說(shuō),學(xué)軟件開(kāi)發(fā)需要學(xué)會(huì)與之相關(guān)的編程語(yǔ)言,常見(jiàn)的軟件開(kāi)發(fā)語(yǔ)言有:JAVA、C語(yǔ)言、C#、C++、JSP、ASP、PB、DELPHI等,而與軟件應(yīng)用最關(guān)鍵的需要用到數(shù)據(jù)庫(kù),我們常說(shuō)的數(shù)據(jù)庫(kù),有:MYSQL、SQLSERVER、ORACLE等。這些都是軟件開(kāi)發(fā)所需要學(xué)習(xí)的開(kāi)發(fā)語(yǔ)言,只有把這些都學(xué)會(huì)了,再多加運(yùn)用和聯(lián)系,你就不愁找不到一份好的工作了。
至于學(xué)習(xí)上述編程語(yǔ)言工具的學(xué)習(xí),需要會(huì)高中英語(yǔ)、數(shù)學(xué)物理方面的基礎(chǔ)知識(shí),所謂的“零基礎(chǔ)”學(xué)編程,指的是編程語(yǔ)言0基礎(chǔ)!
1、開(kāi)始自學(xué)軟件編程課程
編程語(yǔ)言種類(lèi)繁多,各有千秋,在學(xué)習(xí)之前需要明確自己要學(xué)習(xí)哪一門(mén)編程語(yǔ)言。確定之后需要制訂一個(gè)合理的學(xué)習(xí)計(jì)劃,并且持之以恒地執(zhí)行學(xué)習(xí)計(jì)劃。在學(xué)習(xí)過(guò)程中要養(yǎng)成良好的學(xué)習(xí)習(xí)慣。
不愛(ài)研究、坐不住,但凡三天打魚(yú)兩天曬網(wǎng),或者對(duì)計(jì)算機(jī)不喜歡等一類(lèi)人不適合學(xué)習(xí)編程,哪怕一時(shí)努力,最后也不是結(jié)不了業(yè),就是功敗垂成,難以在這條路上走遠(yuǎn)。編程入門(mén)點(diǎn)是興趣。興趣是學(xué)習(xí)的最大動(dòng)力源。需要有恒心有耐心,進(jìn)入這個(gè)行業(yè)并不難,就算你沒(méi)有基礎(chǔ)和經(jīng)驗(yàn),也是可以學(xué)好的。那些創(chuàng)造編程語(yǔ)言的人,創(chuàng)造計(jì)算機(jī)的人也都是從零開(kāi)始的。他們也是在不斷揣摩、不斷學(xué)習(xí)和實(shí)踐之火才獲得成果。沒(méi)有一個(gè)技術(shù)大牛是從一開(kāi)始就什么都會(huì)的,都是從什么也不會(huì)開(kāi)始的。只需你有興趣而且肯努力,可能慢慢就會(huì)發(fā)現(xiàn)學(xué)習(xí)軟件開(kāi)發(fā)也沒(méi)有想象中的那么難。
2、要重視編程基本功
絕大部分行業(yè)內(nèi)的大牛都是經(jīng)歷過(guò)辛苦而又長(zhǎng)期的程序開(kāi)發(fā)學(xué)習(xí)和實(shí)戰(zhàn)進(jìn)程的,假如你想要成為一名優(yōu)秀的程序員,最基本的編碼學(xué)習(xí)肯定是不能跳過(guò)的,底層的知識(shí)必需要扎實(shí)掌握,就如同Java開(kāi)發(fā),項(xiàng)目訓(xùn)練前提是掌握一定的java課程基礎(chǔ),假如不先把基礎(chǔ)穩(wěn)固,就直接做項(xiàng)目的話(huà),是很難做出來(lái)而且學(xué)不會(huì)那種邏輯思考的能力。
3、附加技能的學(xué)習(xí)
前面說(shuō)了軟件開(kāi)發(fā)涉及到一種邏輯思維,那么必定要學(xué)習(xí)一些數(shù)學(xué)知識(shí),學(xué)會(huì)數(shù)學(xué)公式的運(yùn)算。軟件開(kāi)發(fā)行業(yè)是特別注重效率的,假如你編寫(xiě)的某個(gè)功能的邏輯不是很清楚,可能整個(gè)項(xiàng)目都會(huì)繞一個(gè)很大的圈子,這樣的代碼存在許多冗余成分,浪費(fèi)很多時(shí)間,所以要懂得培養(yǎng)自己必定的邏輯思維。其次就是英語(yǔ)的學(xué)習(xí)了,雖然學(xué)軟件開(kāi)發(fā)不需要有很強(qiáng)的英語(yǔ)能力,但有必定的英語(yǔ)才能的話(huà),更加有利于自己往更深邃的技術(shù)發(fā)展。
4、動(dòng)手能力的培養(yǎng)
作為一個(gè)程序員動(dòng)手能力是非常重要的,你學(xué)習(xí)的各個(gè)知識(shí)點(diǎn)和思維都自己去開(kāi)發(fā)操練才能穩(wěn)固,作為老師最怕的學(xué)生就是他們只停留在書(shū)本或許課堂上的了解,而自己不去實(shí)實(shí)在在的把它完成出來(lái),著手做的過(guò)程中你會(huì)不斷發(fā)現(xiàn)問(wèn)題,然后自己去解決問(wèn)題,這樣你才能成為一個(gè)真正的高手。也要學(xué)會(huì)找到有效的學(xué)習(xí)辦法,這樣學(xué)起來(lái)會(huì)如魚(yú)得水的??梢韵瓤匆曨l學(xué)習(xí),學(xué)起來(lái)就比曾經(jīng)看書(shū)快許多,并且也更簡(jiǎn)略,覺(jué)得自己掌握了一定的知識(shí)后,可以嘗試做項(xiàng)目,從小項(xiàng)目開(kāi)始練手到商業(yè)項(xiàng)目實(shí)戰(zhàn),懂得實(shí)操的軟件開(kāi)發(fā)工程師才是企業(yè)真正喜歡的。
1、Web開(kāi)發(fā)領(lǐng)域。Web開(kāi)發(fā)是當(dāng)前一個(gè)重要的開(kāi)發(fā)領(lǐng)域,Web開(kāi)發(fā)涉及到的應(yīng)用領(lǐng)域也十分廣泛,可以說(shuō)有互聯(lián)網(wǎng)的地方就有Web軟件。Web開(kāi)發(fā)分為前端開(kāi)發(fā)和后端開(kāi)發(fā)兩大部分,前端開(kāi)發(fā)需要學(xué)習(xí)三個(gè)基本知識(shí),包括Html、CSS和JavaScript,其中JavaScript是重點(diǎn)也是難點(diǎn)。后端開(kāi)發(fā)可以采用眾多開(kāi)發(fā)語(yǔ)言,其中比較流行的編程語(yǔ)言包括PHP、Java和Python。另外,Web開(kāi)發(fā)還需要掌握數(shù)據(jù)庫(kù)知識(shí)以及云計(jì)算平臺(tái)的相關(guān)知識(shí)(IaaS、PaaS)。
2、移動(dòng)端開(kāi)發(fā)。隨著移動(dòng)互聯(lián)網(wǎng)的發(fā)展,目前移動(dòng)端開(kāi)發(fā)的任務(wù)也比較多,移動(dòng)端開(kāi)發(fā)集中在三個(gè)領(lǐng)域,分別是Android開(kāi)發(fā)、iOS開(kāi)發(fā)和各種小程序開(kāi)發(fā)。其中Android開(kāi)發(fā)需要學(xué)習(xí)Java或者kotlin語(yǔ)言,而iOS開(kāi)發(fā)需要學(xué)習(xí)OC或者Swift,小程序開(kāi)發(fā)則需要掌握其對(duì)應(yīng)的開(kāi)發(fā)語(yǔ)言,大部分小程序開(kāi)發(fā)語(yǔ)言都屬于類(lèi)前端開(kāi)發(fā)語(yǔ)言,還是比較容易掌握的。
3、嵌入式開(kāi)發(fā)領(lǐng)域。隨著5G標(biāo)準(zhǔn)的落地應(yīng)用,未來(lái)嵌入式開(kāi)發(fā)領(lǐng)域?qū)⑨尫懦龃罅康拈_(kāi)發(fā)任務(wù),包括大量的可穿戴設(shè)備開(kāi)發(fā)等等。嵌入式開(kāi)發(fā)涉及到三方面內(nèi)容,分別是設(shè)備(各種傳感器等)、網(wǎng)絡(luò)和平臺(tái),編程語(yǔ)言通??梢詮腃語(yǔ)言開(kāi)始學(xué)起。
4、最后,不論從事哪個(gè)領(lǐng)域的開(kāi)發(fā),都應(yīng)該具備扎實(shí)的計(jì)算機(jī)基礎(chǔ)知識(shí),包括操作系統(tǒng)(體系結(jié)構(gòu))、計(jì)算機(jī)網(wǎng)絡(luò)、數(shù)據(jù)庫(kù)等。如果想走研發(fā)級(jí)程序員路線(xiàn),一定要重視數(shù)學(xué)基礎(chǔ),另外需要系統(tǒng)的學(xué)習(xí)算法設(shè)計(jì)、數(shù)據(jù)結(jié)構(gòu)和編譯原理等內(nèi)容。
前端開(kāi)發(fā)的難點(diǎn)在掌握HTML。
掌握HTML是前端開(kāi)發(fā)的核心,HTML是一種制作萬(wàn)維網(wǎng)頁(yè)面的標(biāo)準(zhǔn)語(yǔ)言,是萬(wàn)維網(wǎng)瀏覽器使用的一種語(yǔ)言,它消除了不同計(jì)算機(jī)之間信息交流的障礙。
因此,它是網(wǎng)絡(luò)上應(yīng)用最為廣泛的語(yǔ)言,也是構(gòu)成網(wǎng)頁(yè)文檔的主要語(yǔ)言,學(xué)好HTML是成為Web開(kāi)發(fā)人員的基本條件。
常見(jiàn)前端開(kāi)發(fā)工程師職位職責(zé)要求:
1、使用Div+css并結(jié)合Javascript負(fù)責(zé)產(chǎn)品的前端開(kāi)發(fā)和頁(yè)面制作。
2、熟悉W3C標(biāo)準(zhǔn)和各主流瀏覽器在前端開(kāi)發(fā)中的差異,能熟練運(yùn)用DIV+CSS,提供針對(duì)不同瀏覽器的前端頁(yè)面解決方案。移動(dòng)HTML5的性能和其他優(yōu)化,為用戶(hù)呈現(xiàn)最好的界面交互體驗(yàn)和最好的性能。
3、負(fù)責(zé)相關(guān)產(chǎn)品的需求以及前端程序的實(shí)現(xiàn),提供合理的前端架構(gòu)。改進(jìn)和優(yōu)化開(kāi)發(fā)工具、開(kāi)發(fā)流程、和開(kāi)發(fā)框架。
4、與產(chǎn)品、后臺(tái)開(kāi)發(fā)人員保持良好溝通,能快速理解、消化各方需求,并落實(shí)為具體的開(kāi)發(fā)工作,能獨(dú)立完成功能頁(yè)面的設(shè)計(jì)與代碼編寫(xiě),配合產(chǎn)品團(tuán)隊(duì)完成功能頁(yè)面的需求調(diào)研和分析。
一、JavaScript異步編程的兩個(gè)核心難點(diǎn)
異步I/O、事件驅(qū)動(dòng)使得單線(xiàn)程的JavaScript得以在不阻塞UI的情況下執(zhí)行網(wǎng)絡(luò)、文件訪問(wèn)功能,且使之在后端實(shí)現(xiàn)了較高的性能。然而異步風(fēng)格也引來(lái)了一些麻煩,其中比較核心的問(wèn)題是:
1、函數(shù)嵌套過(guò)深
JavaScript的異步調(diào)用基于回調(diào)函數(shù),當(dāng)多個(gè)異步事務(wù)多級(jí)依賴(lài)時(shí),回調(diào)函數(shù)會(huì)形成多級(jí)的嵌套,代碼變成
金字塔型結(jié)構(gòu)。這不僅使得代碼變難看難懂,更使得調(diào)試、重構(gòu)的過(guò)程充滿(mǎn)風(fēng)險(xiǎn)。
2、異常處理
回調(diào)嵌套不僅僅是使代碼變得雜亂,也使得錯(cuò)誤處理更復(fù)雜。這里主要講講異常處理。
二、異常處理
像很多時(shí)髦的語(yǔ)言一樣,JavaScript 也允許拋出異常,隨后再用一個(gè)try/catch
語(yǔ)句塊捕獲。如果拋出的異常未被捕獲,大多數(shù)JavaScript環(huán)境都會(huì)提供一個(gè)有用的堆棧軌跡。舉個(gè)例子,下面這段代碼由于'{'為無(wú)效JSON
對(duì)象而拋出異常。
?
12345678
function JSONToObject(jsonStr) { return JSON.parse(jsonStr);}var obj = JSONToObject('{');//SyntaxError: Unexpected end of input//at Object.parse (native)//at JSONToObject (/AsyncJS/stackTrace.js:2:15)//at Object.anonymous (/AsyncJS/stackTrace.js:4:11)
堆棧軌跡不僅告訴我們哪里拋出了錯(cuò)誤,而且說(shuō)明了最初出錯(cuò)的地方:第4 行代碼。遺憾的是,自頂向下地跟蹤異步錯(cuò)誤起源并不都這么直截了當(dāng)。
異步編程中可能拋出錯(cuò)誤的情況有兩種:回調(diào)函數(shù)錯(cuò)誤、異步函數(shù)錯(cuò)誤。
1、回調(diào)函數(shù)錯(cuò)誤
如果從異步回調(diào)中拋出錯(cuò)誤,會(huì)發(fā)生什么事?讓我們先來(lái)做個(gè)測(cè)試。
?
1234567
setTimeout(function A() { setTimeout(function B() { setTimeout(function C() { throw new Error('Something terrible has happened!'); }, 0); }, 0);}, 0);
上述應(yīng)用的結(jié)果是一條極其簡(jiǎn)短的堆棧軌跡。
?
12
Error: Something terrible has happened!at Timer.C (/AsyncJS/nestedErrors.js:4:13)
等等,A 和B 發(fā)生了什么事?為什么它們沒(méi)有出現(xiàn)在堆棧軌跡中?這是因?yàn)檫\(yùn)行C 的時(shí)候,異步函數(shù)的上下文已經(jīng)不存在了,A 和B 并不在內(nèi)存堆棧里。這3
個(gè)函數(shù)都是從事件隊(duì)列直接運(yùn)行的?;谕瑯拥睦碛?,利用try/catch
語(yǔ)句塊并不能捕獲從異步回調(diào)中拋出的錯(cuò)誤。另外回調(diào)函數(shù)中的return也失去了意義。
?
1234567
try { setTimeout(function() { throw new Error('Catch me if you can!'); }, 0);} catch (e) {console.error(e);}
看到這里的問(wèn)題了嗎?這里的try/catch 語(yǔ)句塊只捕獲setTimeout函數(shù)自身內(nèi)部發(fā)生的那些錯(cuò)誤。因?yàn)閟etTimeout
異步地運(yùn)行其回調(diào),所以即使延時(shí)設(shè)置為0,回調(diào)拋出的錯(cuò)誤也會(huì)直接流向應(yīng)用程序。
總的來(lái)說(shuō),取用異步回調(diào)的函數(shù)即使包裝上try/catch 語(yǔ)句塊,也只是無(wú)用之舉。(特例是,該異步函數(shù)確實(shí)是在同步地做某些事且容易出錯(cuò)。例如,Node
的fs.watch(file,callback)就是這樣一個(gè)函數(shù),它在目標(biāo)文件不存在時(shí)會(huì)拋出一個(gè)錯(cuò)誤。)正因?yàn)榇?,Node.js
中的回調(diào)幾乎總是接受一個(gè)錯(cuò)誤作為其首個(gè)參數(shù),這樣就允許回調(diào)自己來(lái)決定如何處理這個(gè)錯(cuò)誤。
2、異步函數(shù)錯(cuò)誤
由于異步函數(shù)是立刻返回的,異步事務(wù)中發(fā)生的錯(cuò)誤是無(wú)法通過(guò)try-catch來(lái)捕捉的,只能采用由調(diào)用方提供錯(cuò)誤處理回調(diào)的方案來(lái)解決。
例如Node中常見(jiàn)的function (err, ...)
{...}回調(diào)函數(shù),就是Node中處理錯(cuò)誤的約定:即將錯(cuò)誤作為回調(diào)函數(shù)的第一個(gè)實(shí)參返回。再比如HTML5中FileReader對(duì)象的onerror函數(shù),會(huì)被用于處理異步讀取文件過(guò)程中的錯(cuò)誤。
舉個(gè)例子,下面這個(gè)Node 應(yīng)用嘗試異步地讀取一個(gè)文件,還負(fù)責(zé)記錄下任何錯(cuò)誤(如“文件不存在”)。
?
1234567
var fs = require('fs'); fs.readFile('fhgwgdz.txt', function(err, data) { if (err) { return console.error(err); }; console.log(data.toString('utf8'));});
客戶(hù)端JavaScript 庫(kù)的一致性要稍微差些,不過(guò)最常見(jiàn)的模式是,針對(duì)成敗這兩種情形各規(guī)定一個(gè)單獨(dú)的回調(diào)。jQuery 的Ajax
方法就遵循了這個(gè)模式。
?
1234
$.get('/data', { success: successHandler, failure: failureHandler});
不管API 形態(tài)像什么,始終要記住的是,只能在回調(diào)內(nèi)部處理源于回調(diào)的異步錯(cuò)誤。
三、未捕獲異常的處理
如果是從回調(diào)中拋出異常的,則由那個(gè)調(diào)用了回調(diào)的人負(fù)責(zé)捕獲該異常。但如果異常從未被捕獲,又會(huì)怎么樣?這時(shí),不同的JavaScript環(huán)境有著不同的游戲規(guī)則……
1. 在瀏覽器環(huán)境中
現(xiàn)代瀏覽器會(huì)在開(kāi)發(fā)人員控制臺(tái)顯示那些未捕獲的異常,接著返回事件隊(duì)列。要想修改這種行為,可以給window.onerror
附加一個(gè)處理器。如果windows.onerror 處理器返回true,則能阻止瀏覽器的默認(rèn)錯(cuò)誤處理行為。
?
123
window.onerror = function(err) { return true; //徹底忽略所有錯(cuò)誤};
在成品應(yīng)用中, 會(huì)考慮某種JavaScript 錯(cuò)誤處理服務(wù), 譬如Errorception。Errorception
提供了一個(gè)現(xiàn)成的windows.onerror 處理器,它向應(yīng)用服務(wù)器報(bào)告所有未捕獲的異常,接著應(yīng)用服務(wù)器發(fā)送消息通知我們。
2. 在Node.js 環(huán)境中
在Node 環(huán)境中,window.onerror 的類(lèi)似物就是process 對(duì)象的uncaughtException 事件。正常情況下,Node
應(yīng)用會(huì)因未捕獲的異常而立即退出。但只要至少還有一個(gè)uncaughtException 事件處理
器,Node 應(yīng)用就會(huì)直接返回事件隊(duì)列。
?
123
process.on('uncaughtException', function(err) { console.error(err); //避免了關(guān)停的命運(yùn)!});
但是,自Node 0.8.4 起,uncaughtException 事件就被廢棄了。據(jù)其文檔所言,對(duì)異常處理而言,uncaughtException
是一種非常粗暴的機(jī)制,請(qǐng)勿使用uncaughtException,而應(yīng)使用Domain 對(duì)象。
Domain 對(duì)象又是什么?你可能會(huì)這樣問(wèn)。Domain 對(duì)象是事件化對(duì)象,它將throw 轉(zhuǎn)化為'error'事件。下面是一個(gè)例子。
?
123456789
var myDomain = require('domain').create();myDomain.run(function() { setTimeout(function() { throw new Error('Listen to me!') }, 50);});myDomain.on('error', function(err) { console.log('Error ignored!');});
源于延時(shí)事件的throw 只是簡(jiǎn)單地觸發(fā)了Domain 對(duì)象的錯(cuò)誤處理器。
Error ignored!
很奇妙,是不是?Domain 對(duì)象讓throw
語(yǔ)句生動(dòng)了很多。不管在瀏覽器端還是服務(wù)器端,全局的異常處理器都應(yīng)被視作最后一根救命稻草。請(qǐng)僅在調(diào)試時(shí)才使用它。
四、幾種解決方案
下面對(duì)幾種解決方案的討論主要集中于上面提到的兩個(gè)核心問(wèn)題上,當(dāng)然也會(huì)考慮其他方面的因素來(lái)評(píng)判其優(yōu)缺點(diǎn)。
1、Async.js
首先是Node中非常著名的Async.js,這個(gè)庫(kù)能夠在Node中展露頭角,恐怕也得歸功于Node統(tǒng)一的錯(cuò)誤處理約定。
而在前端,一開(kāi)始并沒(méi)有形成這么統(tǒng)一的約定,因此使用Async.js的話(huà)可能需要對(duì)現(xiàn)有的庫(kù)進(jìn)行封裝。
Async.js的其實(shí)就是給回調(diào)函數(shù)的幾種常見(jiàn)使用模式加了一層包裝。比如我們需要三個(gè)前后依賴(lài)的異步操作,采用純回調(diào)函數(shù)寫(xiě)法如下:
?
12345678910111213141516
asyncOpA(a, b, (err, result) = { if (err) { handleErrorA(err); } asyncOpB(c, result, (err, result) = { if (err) { handleErrorB(err); } asyncOpB(d, result, (err, result) = { if (err) { handlerErrorC(err); } finalOp(result); }); });});
如果我們采用async庫(kù)來(lái)做:
?
12345678910111213141516171819202122
async.waterfall([ (cb) = { asyncOpA(a, b, (err, result) = { cb(err, c, result); }); }, (c, lastResult, cb) = { asyncOpB(c, lastResult, (err, result) = { cb(err, d, result); }) }, (d, lastResult, cb) = { asyncOpC(d, lastResult, (err, result) = { cb(err, result); }); }], (err, finalResult) = { if (err) { handlerError(err); } finalOp(finalResult);});
可以看到,回調(diào)函數(shù)由原來(lái)的橫向發(fā)展轉(zhuǎn)變?yōu)榭v向發(fā)展,同時(shí)錯(cuò)誤被統(tǒng)一傳遞到最后的處理函數(shù)中。
其原理是,將函數(shù)數(shù)組中的后一個(gè)函數(shù)包裝后作為前一個(gè)函數(shù)的末參數(shù)cb傳入,同時(shí)要求:
每一個(gè)函數(shù)都應(yīng)當(dāng)執(zhí)行其cb參數(shù);cb的第一個(gè)參數(shù)用來(lái)傳遞錯(cuò)誤。我們可以自己寫(xiě)一個(gè)async.waterfall的實(shí)現(xiàn):
?
12345678910111213141516171819202122
let async = { waterfall: (methods, finalCb = _emptyFunction) = { if (!_isArray(methods)) { return finalCb(new Error('First argument to waterfall must be an array of functions')); } if (!methods.length) { return finalCb(); } function wrap(n) { if (n === methods.length) { return finalCb; } return function (err, ...args) { if (err) { return finalCb(err); } methods[n](...args, wrap(n + 1)); } } wrap(0)(false); }};
Async.js還有series/parallel/whilst等多種流程控制方法,來(lái)實(shí)現(xiàn)常見(jiàn)的異步協(xié)作。
Async.js的問(wèn)題:
在外在上依然沒(méi)有擺脫回調(diào)函數(shù),只是將其從橫向發(fā)展變?yōu)榭v向,還是需要程序員熟練異步回調(diào)風(fēng)格。
錯(cuò)誤處理上仍然沒(méi)有利用上try-catch和throw,依賴(lài)于“回調(diào)函數(shù)的第一個(gè)參數(shù)用來(lái)傳遞錯(cuò)誤”這樣的一個(gè)約定。
2、Promise方案
ES6的Promise來(lái)源于Promise/A+。使用Promise來(lái)進(jìn)行異步流程控制,有幾個(gè)需要注意的問(wèn)題,
把前面提到的功能用Promise來(lái)實(shí)現(xiàn),需要先包裝異步函數(shù),使之能返回一個(gè)Promise:
?
12345678910
function toPromiseStyle(fn) { return (...args) = { return new Promise((resolve, reject) = { fn(...args, (err, result) = { if (err) reject(err); resolve(result); }) }); };}
這個(gè)函數(shù)可以把符合下述規(guī)則的異步函數(shù)轉(zhuǎn)換為返回Promise的函數(shù):
回調(diào)函數(shù)的第一個(gè)參數(shù)用于傳遞錯(cuò)誤,第二個(gè)參數(shù)用于傳遞正常的結(jié)果。接著就可以進(jìn)行操作了:
?
123456789101112131415
let [opA, opB, opC] = [asyncOpA, asyncOpB, asyncOpC].map((fn) = toPromiseStyle(fn)); opA(a, b) .then((res) = { return opB(c, res); }) .then((res) = { return opC(d, res); }) .then((res) = { return finalOp(res); }) .catch((err) = { handleError(err); });
通過(guò)Promise,原來(lái)明顯的異步回調(diào)函數(shù)風(fēng)格顯得更像同步編程風(fēng)格,我們只需要使用then方法將結(jié)果傳遞下去即可,同時(shí)return也有了相應(yīng)的意義:
在每一個(gè)then的onFullfilled函數(shù)(以及onRejected)里的return,都會(huì)為下一個(gè)then的onFullfilled函數(shù)(以及onRejected)的參數(shù)設(shè)定好值。
如此一來(lái),return、try-catch/throw都可以使用了,但catch是以方法的形式出現(xiàn),還是不盡如人意。
3、Generator方案
ES6引入的Generator可以理解為可在運(yùn)行中轉(zhuǎn)移控制權(quán)給其他代碼,并在需要的時(shí)候返回繼續(xù)執(zhí)行的函數(shù)。利用Generator可以實(shí)現(xiàn)協(xié)程的功能。
將Generator與Promise結(jié)合,可以進(jìn)一步將異步代碼轉(zhuǎn)化為同步風(fēng)格:
?
1234567891011
function* getResult() { let res, a, b, c, d; try { res = yield opA(a, b); res = yield opB(c, res); res = yield opC(d); return res; } catch (err) { return handleError(err); }}
然而我們還需要一個(gè)可以自動(dòng)運(yùn)行Generator的函數(shù):
?
123456789101112131415161718192021222324252627282930
function spawn(genF, ...args) { return new Promise((resolve, reject) = { let gen = genF(...args); function next(fn) { try { let r = fn(); if (r.done) { resolve(r.value); } Promise.resolve(r.value) .then((v) = { next(() = { return gen.next(v); }); }).catch((err) = { next(() = { return gen.throw(err); }) }); } catch (err) { reject(err); } } next(() = { return gen.next(undefined); }); });}
用這個(gè)函數(shù)來(lái)調(diào)用Generator即可:
?
1234567
spawn(getResult) .then((res) = { finalOp(res); }) .catch((err) = { handleFinalOpError(err); });
可見(jiàn)try-catch和return實(shí)際上已經(jīng)以其原本面貌回到了代碼中,在代碼形式上也已經(jīng)看不到異步風(fēng)格的痕跡。
類(lèi)似的功能有co/task.js等庫(kù)實(shí)現(xiàn)。
4、ES7的async/await
ES7中將會(huì)引入async function和await關(guān)鍵字,利用這個(gè)功能,我們可以輕松寫(xiě)出同步風(fēng)格的代碼,
同時(shí)依然可以利用原有的異步I/O機(jī)制。
采用async function,我們可以將之前的代碼寫(xiě)成這樣:
?
12345678910111213
async function getResult() { let res, a, b, c, d; try { res = await opA(a, b); res = await opB(c, res); res = await opC(d); return res; } catch (err) { return handleError(err); }} getResult();
和Generator Promise方案看起來(lái)沒(méi)有太大區(qū)別,只是關(guān)鍵字換了換。
實(shí)際上async
function就是對(duì)Generator方案的一個(gè)官方認(rèn)可,將之作為語(yǔ)言?xún)?nèi)置功能。
async function的缺點(diǎn):
await只能在async function內(nèi)部使用,因此一旦你寫(xiě)了幾個(gè)async function,或者使用了依賴(lài)于async
function的庫(kù),那你很可能會(huì)需要更多的async function。
目前處于提案階段的async
function還沒(méi)有得到任何瀏覽器或Node.JS/io.js的支持。Babel轉(zhuǎn)碼器也需要打開(kāi)實(shí)驗(yàn)選項(xiàng),并且對(duì)于不支持Generator的瀏覽器來(lái)說(shuō),還需要引進(jìn)一層厚厚的regenerator
runtime,想在前端生產(chǎn)環(huán)境得到應(yīng)用還需要時(shí)間。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助。
本文標(biāo)題:javascript難點(diǎn),js難點(diǎn)看這一篇就夠了
本文鏈接:http://aaarwkj.com/article10/dsisjgo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供服務(wù)器托管、定制開(kāi)發(fā)、App設(shè)計(jì)、定制網(wǎng)站、網(wǎng)站制作、關(guān)鍵詞優(yōu)化
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶(hù)投稿、用戶(hù)轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話(huà):028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)