寶馬豐田或將合作開發新能源汽車

寶馬和豐田公司多年來一直在燃料電池技術和汽車羽量級元件方面有著密切合作,未來很有可能合作研發跑車,各自品牌也將通過這次合作推出新車型。在日內瓦車展前,豐田公司集團執行副總裁迪迪爾•勒羅伊就公開表示,目前公司的三個項目都在順利進行中,豐田和寶馬兩大公司都期待在研發跑車這個專案上有所合作。

勒羅伊說道:“雙方公司都在積極促成合作成功,我們都希望可以研發出一款跑車。我們已確定車身架構以及所使用的動力系統。現在我們只需確定啟動項目的時間。”勒羅伊並沒有對外透露可能的時間。

去年豐田汽車在歐洲的銷量占生產總量的70%。豐田公司表示今年希望可以通過增加兩款車型來提高銷售量,兩款車型分別為土耳其工廠製造的C-HR以及在俄羅斯裝配的RAV4。范•吉爾表示公司致力於發展開拓俄羅斯市場,儘管目前挑戰還很嚴峻。2015年豐田俄羅斯分公司銷售額直降36%,僅銷售160萬輛汽車。
 

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

※專營大陸快遞台灣服務

台灣快遞大陸的貨運公司有哪些呢?

英國將在公共道理上開測無人駕駛卡車車隊

Google已經測試無人駕駛小汽車多年,而這項技術的下一階段,則是無人駕駛貨車。由於擺脫了傳統貨車駕駛員所必須的睡眠休息時間,無人駕駛卡車將能夠讓長途運輸變得比以往更快。

據悉,英國將於今年晚些時候開測無人駕駛卡車車隊,不過它不僅僅是為了提升物流的速度,還有望減輕道路的擁塞狀況。

在不久的將來,人們將能夠在M6高速路上見到高達10輛的無人駕駛貨車車隊。此外,儘管測試是在公共道路上進行,但有關方面會盡可能地將影響和潛在問題降到最低。

當然,這並不是我們首次見到無人駕駛貨車車隊的測試。此前,戴姆勒也曾在德國進行過類似的試驗,只是它仍然需要一個人類駕駛員作為後備。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務

特斯拉將推全新電動車Model S P100D 續航里程可達530公里

據外媒報導,特斯拉將推出Model S P100D車型,新車的綜合性能更強,最大續航里程可達530公里。

Model S P90D與Model S P85D相同,都採用了前後雙電動馬達的配置,但前者進一步強化了電動馬達的馬力輸出表現,安置於前輪的電動馬達可輸出190千瓦的最大功率,後輪的電動馬達則可提供高達370千瓦的最大功率,使得Model S P90D的最大綜合輸出馬力達到驚人的560千瓦。在Model S P90D車型上,特斯拉還新增了動力更加強勁的Ludicrous競速模式,它可讓車輛百公里加速秒數縮短10%,僅需2.8秒即可完成,極速則可達到250公里/小時。

在動力系統方面,Model S P100D車型將搭載功率為100千瓦時的電池里程套件,並搭載雙電機,以及四驅系統。新車的百公里加速時間為2.7秒,最大續航里程可能超過530公里。相較於特斯拉旗下的現款最強車型Model S P90D增加了40公里的續航里程,並縮短了0.6秒的百公里加速時間。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

台北網頁設計公司這麼多,該如何挑選?? 網頁設計報價省錢懶人包”嚨底家”

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

小三通海運與一般國際貿易有何不同?

小三通快遞通關作業有哪些?

奔馳下一代汽車將棄用特斯拉電動傳動系統 採用自家技術

戴姆勒電動汽車主管哈拉爾德•克勒格爾(Harald Kroeger)在接受德國媒體採訪時說,為了開發自有傳動系統和電池技術,奔馳已經投資了5.5億美元,下一代B級Electric Drive電動汽車不會使用特斯拉傳動系統。

奔馳這樣做合情合理。2014年年末時,奔馳基本上已經清空了特斯拉持股。在2014年的年報中特斯拉也說B級車研發合作已經基本完成。到了2015年年底,特斯拉已經銷售10萬輛電動汽車。以前特斯拉是矽谷新崛起的明星企業,一些大型汽車公司有興趣與它合作,現在汽車公司已經將特斯拉當成了競爭對手。比如豐田,在特斯拉成立之初,豐田也曾參與投資,特斯拉還為豐田電動版RAV4提供傳動系統。

那時的特斯拉還很年輕,它還沒有推出Model S轎車,如果能與大型汽車商合作對公司的發展無疑是有利的。特斯拉需要增加營收,只有有了營收,公司才有可能轉變為主流汽車製造商。另外,在公司沒有上市之前,它需要吸引早期投資者來支援自己。今天的特斯拉已經完全不同了,Model S大獲成功,Model X剛剛開始向用戶交貨。本月晚些時候Model 3也將上市,這是一款低價電動汽車。可以說現在的特斯拉已經是一家規模雖小但是卻很成熟的電動汽車製造商了。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※想知道網站建置網站改版該如何進行嗎?將由專業工程師為您規劃客製化網頁設計後台網頁設計

※不管是台北網頁設計公司台中網頁設計公司,全省皆有專員為您服務

※Google地圖已可更新顯示潭子電動車充電站設置地點!!

※帶您來看台北網站建置台北網頁設計,各種案例分享

小三通物流營運型態?

※快速運回,大陸空運推薦?

柯文哲訪美西 特斯拉初體驗

台北市長柯文哲近日參訪美國舊金山,並於10日拜訪全球知名的電動車大廠特斯拉汽車公司(Tesla Motors, Inc.),與特斯拉交換電動車友善城市的意見。

由Elon Musk與史丹佛碩士JB Straul聯手打造的特斯拉,是目前知名度最高的電動車製造商。特斯拉將自己定位為「科技產業」,除生產純電動汽車外,也加入自動駕駛等功能。同時,特斯拉搭載的儲能裝置採用鋰電池,其鋰電池技術也透過品牌「Tesla Energy」開始提供Powerwall、Powerpack家用與商用儲能系統。

柯文哲在美西時間10日下午參訪特斯拉,並試乘價值8 萬美金的特斯拉Model X 經典車款。台北市政府表示,柯文哲安排本次參訪的目的,是為了向特斯拉請益如何打造電動車友善城市,並與對方交流意見。

在台北市,目前能見度最高的電動車為電動機車Gogoro。Gogoro致力於打造智慧城市,透過電池交換系統來提供車輛行駛時所需的電力,同時在北、北、基、桃、竹都設有電池交換站,提高民眾採購Gogoro的意願。

(照片來源:台北市政府)

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

網頁設計公司推薦更多不同的設計風格,搶佔消費者視覺第一線

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※自行創業 缺乏曝光? 下一步"網站設計"幫您第一時間規劃公司的門面形象

台灣寄大陸海運貨物規則及重量限制?

大陸寄台灣海運費用試算一覽表

南投搬家前需注意的眉眉角角,別等搬了再說!

寶馬未來百年發力電動車 將在中國實現“國產”

德國慕尼克報導寶馬集團於日前舉辦百年慶典之際,不僅宣佈企業正式進入下一個百年,同時寶馬集團董事長科魯格先生還表示:“我們在多種技術上進行投資,並持續在電動化領域的投入。”根據寶馬集團的規劃,未來每一款產品都會推出插電式混合動力車型。

對於寶馬在華新能源佈局,寶馬集團大中華區總裁兼首席執行官康思遠先生于近日在慕尼克的寶馬總部與車王雜誌溝通時透露:“未來我們將推出更多插電式混合動力車型,寶馬在華的瀋陽工廠正在建設高壓電池中心,是我們為長期發展所做出的投資。”這也將成為國內首個在華建設動力電池的豪華車製造商,並為後續的寶馬插電式混合動力車型提供電池。目前,寶馬已在華投產首款插電式混合動力車型530Le,後續有望再基於2系旅行車、新3系以及全新X1打造的3款國產插電混合動力車。

根據寶馬的新車規劃,全新一代X1將在2016年中實現投產,這款SUV將推出標準軸距版和長軸距版,其中長軸距版將推出三排七座的車型。此外,全新X1還將推出一款插電混動版車型,網通社從國家工商行政管理總局商標局獲悉,寶馬股份公司已在華註冊了“xDrive25Le”商標。其中xDrive25Le中“Le”是指加長版插電式混合動力車,與5系插電混動版530Le的含義相同。新車將搭載由1.5升三缸渦輪增壓汽油發動機和一台後置電動機組成混動系統,總功率輸出可達142千瓦,預計綜合油耗將保持2L左右的水準。

今年3月21日,創新寶馬2系旅行車將實現在華投產上市,基於新車型所打造的插電混動版本也有望投產。現階段,寶馬2系旅行車的插電混動版(225xe)已在海外推出,並搭載的混動系統由1.5T發動機和一款動力輸出可達65千瓦和165牛米電動機組成,當發動機和電動機同時做功時,這套插電式混合動力系統的綜合最大功率為165千瓦,峰值扭矩達到385牛米,百公里綜合油耗僅在2L左右。

除2系旅行車和全新X1之外,目前在華投產的3系轎車也有望推出插電混合動力版車型。此前寶馬已在國際車展上發佈了3系的插電式混合動力車型330e。新車在動力上採用的2.0T+電動機的插電混動系統,最大綜合功率可達到185千瓦,峰值扭矩則為420牛米。百公里綜合油耗僅為2L,與現款3系同搭載2.0T發動機的320i車型6.7L/100km相比,油耗下降了約70%。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

大陸寄台灣空運注意事項

大陸海運台灣交貨時間多久?

英國2017年將在高速公路上測試無人汽車

據路透社報導,英國政府宣佈,2017年將首次在高速公路上測試無人駕駛汽車,其目標是到2020年允許無人駕駛汽車行駛在城市街道上。

英國財政部稱,下週三,英國財政大臣喬治•奧斯本(George Osborne)公佈年度預算報告時,將宣佈在高速公路測試無人駕駛汽車的相關計畫,並表示英國政府將提出議案,清除影響無人駕駛汽車技術部署的法規壁壘。

根據英國政府的資料,在全球範圍內,無人駕駛汽車市場的規模近期內將達到9000億英鎊(約合1.29萬億美元),但需要克服一系列法律障礙,包括明確誰為無人駕駛汽車發生的車禍負責等。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※專營大陸空運台灣貨物推薦

台灣空運大陸一條龍服務

※評比南投搬家公司費用收費行情懶人包大公開

南投搬家費用,距離,噸數怎麼算?達人教你簡易估價知識!

系統分析師-軟件水平考試(高級)-理論-系統規劃

系統分析師-軟件水平考試(高級)-理論-系統規劃

前言

系統規劃是什麼東東呢?

通俗點說,就是為了實現企業的戰略目標,分析企業現狀(技術外部)與系統狀況(技術內部),從而提出新的技術要求,對現有系統進行規劃設計等變化。

  1. 目標是實現企業戰略目標;
  2. 分析企業現狀(了解情況了,才能下手唄。站在技術角度,企業現狀就分技術和非技術);
  3. 根據掌握的資料,對接下來的系統開發做出規劃(技術規劃,那是CTO的工作,這裏就直接系統規劃);
  4. 落實規劃,開發或改造系統,從而完成對企業戰略目標的支持。

期間會涉及對一些項目或系統(一個公司會擁有多個項目與多個系統,用於支撐公司產業線)的評估,如機會選擇,可行性分析,效益分析(分析師比架構師多了這些思量與考察,而高項則更為具體)。

XMIND

(圖片絕對清楚。如果看不清楚,請下載,或者在新頁面中打開圖片)

總結

XMIND重難點的解讀

步驟

為了幫助大家更好地理解這部分內容,我們舉個栗子。

這樣說吧,阿里巴巴定下了淘寶雙十一戰略目標。你作為CTO,就要站在公司高層,開始規劃阿里的系統,讓它為雙十一這一戰略目標服務。

具體的實施過程應該是這樣的:

  1. 首先,根據雙十一這一戰略目標,你得分析阿里現在技術環境(可以做出怎樣的改變,業務上是否可以進行一定的妥協等等),並了解系統當前的狀況(是否可以承受住雙十一壓力。承受不了的話,瓶頸在哪裡等等)。無論做什麼,收集信息,了解情況都是首要的。
  2. 其次,站在技術的角度,你需要確定公司信息系統該達到怎樣的目標(更大一些說,應該是技術的目標標準)。比如雙十一這樣的戰略目標,我確定公司的系統應該達到十萬的訂單處理速度(2019年,阿里的訂單創建峰值已經達到了五十萬左右),以及一系列類似的系統要求。
  3. 然後,根據前面制定的一系列系統要求。開始規劃系統的拆分,將目標系統進行邏輯的拆分。但是如果已經有了系統基礎,那麼就需要在原有的系統上,進行調整。如阿里雲平台必須保證在雙十一時提供足夠強大的基礎設施支撐(可以在必要時,支撐大當量的橫向擴展)。又如支付寶需要確保在雙十一零點(流量衝擊的峰值)保證可以支撐百萬計的支付請求,並且妥善處理超出的部分。這樣就完成了目標的落地方案生成。
  4. 接下來,需要確定工作的優先級別,以及開發順序。由於總的開發資源是有限的,並且不同業務之間存在各種錯綜複雜的關係,所以,需要CTO站在公司高層角度,進行這個層次的方案安排。如由於阿里雲是其它業務的支撐基礎,是實現目標的必要因素(甚至都沒有太多業務妥協的空間),那麼我們可以將它作為優先級第一的工作,並最大程度地傾斜企業資源等。其它工作以此類推。從複雜的角度,可以了解項目組合管理,以及企業戰略管理等(但是分析師考試不會這麼複雜的,這裏只是舉個栗子)。
  5. 接着,我需要對這些方案進行可行性分析。畢竟這些方案可能是我根據自己的經驗,以及周邊個別的意見,花了一天的時間整合出來的。其中可能存在一些不合理,不科學的部分,而我並不了解(個人的力量與認知畢竟有限。也許我對軟件十分清楚,但是在硬件上提出了超脫物理規律的不可能方案,而我想當然地認為可以)。所以,需要進行可行性分析。甚至通過論證會議,進行具體的論證,從而確定方案是否可行,是否需要調整。
  6. 最後,根據前面這些簡要的方案與意見,通過自己與下屬不斷溝通,從而形成一份具體的系統設計的方案-系統設計任務書。作為接下來實施系統建設工作的具體依據。

可行性分析

這裏着重提一下這個部分,這個部分充分體現了系統的業務特性。

從考試角度說,這個部分雖然不是一個章節,但是每次考試都會考幾分。

從實際角度來說,可能一些感興趣的比較清楚,阿里的p7-p8,騰訊的t3-t4,晉陞都是有一定困難的。晉陞條件中有一條,需要對業務有足夠的了解。就如同國外對程序員的分級看法,也對程序員的產品思維有着非常重的要求。大廠要求程序員對業務有一定的了解,一方面是確定經歷真實性,另一方面就是觀察面試者的業務思維,產品思維。可能p7,只是要求根據業務場景,實現業務方案,並適當根據技術,提出對業務的看法(如調整業務,提出新的業務特性等)。到了p8-p9就是希望你能在一個大的目標下,提出自己的產品理念。在項目經理的產品模型或產品想法的基礎上,站在技術角度,給出新的產品想法,去完善產品模型,提高產品的層次。

以上看法,不保證完全正確,畢竟不同人的解讀是不同的。但是還是值得參考一下的(日後我晉陞p8,p9,考慮回來更新一下)。

那麼可行性分析可以帶來產品思維嘛?

當然,,,不能。

但是,可行性分析,絕對是一個絕佳的入門機會。可以幫助開發人員,從一個新的角度去看待自己開發的系統。並且這個入門的門檻很低,開發人員可以很好的理解,入門。後續的道路,就需要各位自己走了。畢竟完事開頭難,開始解決了,後面走下去就行了。當然後續有更多積累了,我會分享我對產品,業務的看法。

至於其它部分,都比較簡單,就不在此深入談論了。

學習必要性

考試的必要性,我只說一句,分值可觀。

現實的意義,我總結了三點比較重要的:

  • 提升高度。通過這部分的學習,可以為你晉陞公司技術高層埋下一顆種子。起碼你和Boss扯皮的時候,不再是只有技術名詞了。
  • 改善眼界。通過這部分的學習,可以改變你對信息系統的純技術看法。有時候,人的改變,只是需要一個開始。
  • 心中有數。通過這部分的學習,可以令你明白現有項目的一些基本商業特性。起碼你知道你的項目能走多遠,是不是該跑路了。囧

這個章節就這些內容,如果有什麼不清楚的,可以@我。如果有正在準備考試或已經通過考試的,或有交流需求的,可以@我,加群。

希望這篇博客對大家有所幫助。

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

文件上傳

文件上傳是 Web 開發常見需求,上傳文件需要用到文件輸入框,如果給文件輸入框添加一個 multiple 屬性則可以一次選擇多個文件(不支持的瀏覽器會自動忽略這個屬性)

<input multiple type="file">

點擊這個輸入框就可以打開瀏覽文件對話框選擇文件了,一般一個輸入框上傳一個文件就行,要上傳多個文件也可以用多個輸入框來處理,這樣做是為了兼容那些不支持 multiple 屬性的瀏覽器,同時用戶一般也不會選擇多個文件

基本上傳方式

當把文件輸入框放入表單中,提交表單的時候即可將選中的文件一起提交上傳到服務器,需要注意的是由於提交的表單中包含文件,因此要修改一下錶單元素的 enctype 屬性為 multipart/form-data

<form action="#" enctype="multipart/form-data" method="post">
  <input name="file" type="file">
  <button type="submit">Upload</button>
</form>

這樣上傳方式是傳統的同步上傳,上傳的文件如果很大,往往需要等待很久,上傳完成后頁面還會重新加載,並且必須等待上傳完成后才能繼續操作

早期的瀏覽器並不支持異步上傳,不過可以使用 iframe 來模擬,在頁面中隱藏一個 <iframe> 元素,指定一個 name 值,同時將 <form> 元素的 target 屬性值指定為 <iframe> 元素的 name 屬性的值,將兩者關聯起來

<form action="#" enctype="multipart/form-data" method="post" target="upload-frame">
  <input name="file" type="file">
  <button type="submit">Upload</button>
</form>
<iframe id="upload-frame" name="upload-frame" src="about:blank" style="display: none;"></iframe>

這樣在提交表單上傳的時候,頁面就不會重新加載了,取而代之的是 iframe 重新加載了,不過 iframe 原本就是隱藏的,即使重新加載也不會感知到

訪問文件

File API 提供了訪問文件的能力,通過輸入框的 files 屬性訪問,這會得到一個 FileList,這是一個集合,如果只選擇了一個文件,那麼集合中的第一個元素就是這個文件

var input = document.querySelector('input[type="file"]')
var file = input.files[0]

console.log(file.name) // 文件名稱
console.log(file.size) // 文件大小
console.log(file.type) // 文件類型

支持 File API 的瀏覽器可以參考

Ajax 上傳

由於可以通過 File API 直接訪問文件內容,再結合 XMLHttpRequest 對象直接將文件上傳,將其作為參數傳給 XMLHttpRequest 對象的 send 方法即可

var xhr = new XMLHttpRequest()
xhr.open('POST', '/upload/url', true)
xhr.send(file)

不過一些原因不建議直接這樣傳遞文件,而是使用 FormData 對象來包裝需要上傳的文件,FormData 是一個構造函數,使用的時候先 new 一個實例,然後通過實例的 append 方法向其中添加數據,直接把需要上傳的文件添加進去

var formData = new FormData()
formData.append('file', file, file.name) // 第 3 個參數是文件名稱
formData.append('username', 'Mary') // 還可以添加額外的參數

甚至也可以直接把表單元素作為實例化參數,這樣整個表單中的數據就全部包含進去了

var formData = new FormData(document.querySelector('form'))

數據準備好后,就是上傳了,同樣是作為參數傳給 XMLHttpRequest 對象的 send 方法

var xhr = new XMLHttpRequest()
xhr.open('POST', '/upload/url', true)
xhr.send(formData)

監測上傳進度

XMLHttpRequest 對象還提供了一個 progress 事件,基於這個事件可以知道上傳進度如何

var xhr = new XMLHttpRequest()
xhr.open('POST', '/upload/url', true)
xhr.upload.onprogress = progressHandler // 這個函數接下來定義

上傳的 progress 事件由 xhr.upload 對象觸發,在事件處理程序中使用這個事件對象的 loaded(已上傳字節數) 和 total(總數) 屬性來計算上傳的進度

function progressHandler(e) {
  var percent = Math.round((e.loaded / e.total) * 100)
}

上面的計算會得到一個表示完成百分比的数字,不過這兩個值也不一定總會有,保險一點先判斷一下事件對象的 lengthComputable 屬性

function progressHandler(e) {
  if (e.lengthComputable) {
    var percent = Math.round((e.loaded / e.total) * 100)
  }
}

支持 Ajax 上傳的瀏覽器可以參考

分割上傳

使用文件對象的 slice 方法可以分割文件,給該方法傳遞兩個參數,一個起始位置和一個結束位置,這會返回一個新的 Blob 對象,包含原文件從起始位置到結束位置的那一部分(文件 File 對象其實也是 Blob 對象,這可以通過 file instanceof Blob 確定,Blob 是 File 的父類)

var blob = file.slice(0, 1024) // 文件從字節位置 0 到字節位置 1024 那 1KB

將文件分割成幾個 Blob 對象分別上傳就能實現將大文件分割上傳

function upload(file) {
  let formData = new FormData()
  formData.append('file', file)
  let xhr = new XMLHttpRequest()
  xhr.open('POST', '/upload/url', true)
  xhr.send(formData)
}

var blob = file.slice(0, 1024)
upload(blob) // 上傳第一部分

var blob2 = file.slice(1024, 2048)
upload(blob2) // 上傳第二部分

// 上傳剩餘部分

通常用一個循環來處理更方便

var pos = 0 // 起始位置
var size = 1024 // 塊的大小

while (pos < file.size) {
  let blob = file.slice(pos, pos + size) // 結束位置 = 起始位置 + 塊大小

  upload(blob)
  pos += size // 下次從結束位置開始繼續分割
}

服務器接收到分塊文件進行重新組裝的代碼就不在這裏展示了

使用這種方式上傳文件會一次性發送多個 HTTP 請求,那麼如何處理這種多個請求同時發送的情況呢?方法有很多,可以用 Promise 來處理,讓每次上傳都返回一個 promise 對象,然後用 Promise.all 方法來合併處理,Promise.all 方法接受一個數組作為參數,因此將每次上傳返回的 promise 對象放在一個數組中

var promises = []

while (pos < file.size) {
  let blob = file.slice(pos, pos + size)

  promises.push(upload(blob)) // upload 應該返回一個 promise
  pos += size
}

同時改造一下 upload 函數使其返回一個 promise

function upload(file) {
  return new Promise((resolve, reject) => {
    let formData = new FormData()
    formData.append('file', file)
    let xhr = new XMLHttpRequest()
    xhr.open('POST', '/upload/url', true)
    xhr.onload = () => resolve(xhr.responseText)
    xhr.onerror = () => reject(xhr.statusText)
    xhr.send(formData)
  })
}

當一切完成后

Promise.all(promises).then((response) => {
  console.log('Upload success!')
}).catch((err) => {
  console.log(err)
})

支持文件分割的瀏覽器可以參考

判斷一下文件對象是否有該方法就能知道瀏覽器是否支持該方法,對於早期的部分版本瀏覽器需要加上對應的瀏覽器廠商前綴

var slice = file.slice || file.webkitSlice || file.mozSlice

if (slice) {
  let blob = slice.call(file, 0, 1024) // call
  upload(blob)
} else {
  upload(file) // 不支持分割就只能直接上傳整個文件了,或者提示文件過大
}

拖拽上傳

通過拖拽 API 可以實現拖拽文件上傳,默認情況下,拖拽一個文件到瀏覽器中,瀏覽器會嘗試打開這個文件,要使用拖拽功能需要阻止這個默認行為

document.addEventListener('dragover', function(e) {
  e.preventDefault()
  e.stopPropagation()
})

任意指定一個元素來作為釋放拖拽的區域,給一個元素綁定 drop 事件

var element = document.querySelector('label')
element.addEventListener('drop', function(e) {
  e.preventDefault()
  e.stopPropagation()

  // ...
})

通過該事件對象的 dataTransfer 屬性獲取文件,然後上傳即可

var file = e.dataTransfer.files[0]
upload(file) // upload 函數前面已經定義

選擇類型

給文件輸入框添加 accept 屬性即可指定選擇文件的類型,比如要選擇 png 格式的圖片,則指定其值為 image/png,如果要允許選擇所有類型的圖片,就是 image/*

<input accept="image/*" type="file">

添加 capture 屬性可以調用設備機能,比如 capture="camera" 可以調用相機拍照,不過這並不是一個標準屬性,不同設備實現方式也不一樣,需要注意

<input accept="image/*" capture="camera" type="file">

經測 iOS 設備添加該屬性后只能拍照而不能從相冊選擇文件了,所以判斷一下

if (iOS) { // iOS 用 navigator.userAgent 判斷
  input.removeAttribute('capture')
}

不支持的瀏覽器會自動忽略這些屬性

自定義樣式

文件輸入框在各個瀏覽器中呈現的樣子都不大相同,而且給 input 定義樣式也不是那麼方便,如果有需要應用自定義樣式,有一個技巧,可以用一個 label 關聯到這個文件輸入框,當點擊這個 label 元素的時候就會觸發文件輸入框的點擊,打開瀏覽文件的對話框,相當於點擊了文件輸入框一樣的效果

<label for="file-input"></label>
<input id="file-input" style="clip: rect(0,0,0,0); position: absolute;" type="file">

這時就可以將原本的文件輸入框隱藏了,然後給 label 元素任意地應用樣式,畢竟要給 label 元素應用樣式比 input 方便得多

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

※為什麼 USB CONNECTOR 是電子產業重要的元件?

網頁設計一頭霧水??該從何著手呢? 找到專業技術的網頁設計公司,幫您輕鬆架站!

※想要讓你的商品成為最夯、最多人討論的話題?網頁設計公司讓你強力曝光

※想知道最厲害的台北網頁設計公司推薦台中網頁設計公司推薦專業設計師”嚨底家”!!

※專營大陸快遞台灣服務

台灣快遞大陸的貨運公司有哪些呢?

【集合系列】- 深入淺出分析LinkedHashMap

一、摘要

在集合系列的第一章,咱們了解到,Map的實現類有HashMap、LinkedHashMap、TreeMap、IdentityHashMap、WeakHashMap、Hashtable、Properties等等。

本文主要從數據結構和算法層面,探討LinkedHashMap的實現。

二、簡介

LinkedHashMap可以認為是HashMap+LinkedList,它既使用HashMap操作數據結構,又使用LinkedList維護插入元素的先後順序,內部採用雙向鏈表(doubly-linked list)的形式將所有元素( entry )連接起來。

LinkedHashMap繼承了HashMap,允許放入key為null的元素,也允許插入value為null的元素。從名字上可以看出該容器是LinkedList和HashMap的混合體,也就是說它同時滿足HashMap和LinkedList的某些特性,可將LinkedHashMap看作採用Linked list增強的HashMap。

打開 LinkedHashMap 源碼,可以看到主要三個核心屬性:

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>{

    /**雙向鏈表的頭節點*/
    transient LinkedHashMap.Entry<K,V> head;

    /**雙向鏈表的尾節點*/
    transient LinkedHashMap.Entry<K,V> tail;

    /**
      * 1、如果accessOrder為true的話,則會把訪問過的元素放在鏈表後面,放置順序是訪問的順序
      * 2、如果accessOrder為false的話,則按插入順序來遍歷
      */
      final boolean accessOrder;
}

LinkedHashMap 在初始化階段,默認按插入順序來遍歷

public LinkedHashMap() {
        super();
        accessOrder = false;
}

LinkedHashMap 採用的 Hash 算法和 HashMap 相同,不同的是,它重新定義了數組中保存的元素Entry,該Entry除了保存當前對象的引用外,還保存了其上一個元素before和下一個元素after的引用,從而在哈希表的基礎上又構成了雙向鏈接列表。

源碼如下:

static class Entry<K,V> extends HashMap.Node<K,V> {
        //before指的是鏈表前驅節點,after指的是鏈表后驅節點
        Entry<K,V> before, after;
        Entry(int hash, K key, V value, Node<K,V> next) {
            super(hash, key, value, next);
        }
}

可以直觀的看出,雙向鏈表頭部插入的數據為鏈表的入口,迭代器遍歷方向是從鏈表的頭部開始到鏈表尾部結束。

除了可以保迭代歷順序,這種結構還有一個好處:迭代LinkedHashMap時不需要像HashMap那樣遍歷整個table,而只需要直接遍歷header指向的雙向鏈表即可,也就是說LinkedHashMap的迭代時間就只跟entry的個數相關,而跟table的大小無關。

三、常用方法介紹

3.1、get方法

get方法根據指定的key值返回對應的value。該方法跟HashMap.get()方法的流程幾乎完全一樣,默認按照插入順序遍歷。

public V get(Object key) {
        Node<K,V> e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
}

如果accessOrdertrue的話,會把訪問過的元素放在鏈表後面,放置順序是訪問的順序

void afterNodeAccess(Node<K,V> e) { // move node to last
        LinkedHashMap.Entry<K,V> last;
        if (accessOrder && (last = tail) != e) {
            LinkedHashMap.Entry<K,V> p =
                (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
            p.after = null;
            if (b == null)
                head = a;
            else
                b.after = a;
            if (a != null)
                a.before = b;
            else
                last = b;
            if (last == null)
                head = p;
            else {
                p.before = last;
                last.after = p;
            }
            tail = p;
            ++modCount;
        }
}

測試用例:

public static void main(String[] args) {
        //accessOrder默認為false
        Map<String, String> accessOrderFalse = new LinkedHashMap<>();
        accessOrderFalse.put("1","1");
        accessOrderFalse.put("2","2");
        accessOrderFalse.put("3","3");
        accessOrderFalse.put("4","4");
        System.out.println("acessOrderFalse:"+accessOrderFalse.toString());
        
        //accessOrder設置為true
        Map<String, String> accessOrderTrue = new LinkedHashMap<>(16, 0.75f, true);
        accessOrderTrue.put("1","1");
        accessOrderTrue.put("2","2");
        accessOrderTrue.put("3","3");
        accessOrderTrue.put("4","4");
        accessOrderTrue.get("2");//獲取鍵2
        accessOrderTrue.get("3");//獲取鍵3
        System.out.println("accessOrderTrue:"+accessOrderTrue.toString());
}

輸出結果:

acessOrderFalse:{1=1, 2=2, 3=3, 4=4}
accessOrderTrue:{1=1, 4=4, 2=2, 3=3}

3.2、put方法

put(K key, V value)方法是將指定的key, value對添加到map里。該方法首先會調用HashMap的插入方法,同樣對map做一次查找,看是否包含該元素,如果已經包含則直接返回,查找過程類似於get()方法;如果沒有找到,將元素插入集合。

/**HashMap 中實現*/
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
}

LinkedHashMap 中覆寫的方法

// LinkedHashMap 中覆寫
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
    LinkedHashMap.Entry<K,V> p =
        new LinkedHashMap.Entry<K,V>(hash, key, value, e);
    // 將 Entry 接在雙向鏈表的尾部
    linkNodeLast(p);
    return p;
}

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
    LinkedHashMap.Entry<K,V> last = tail;
    tail = p;
    // last 為 null,表明鏈表還未建立
    if (last == null)
        head = p;
    else {
        // 將新節點 p 接在鏈表尾部
        p.before = last;
        last.after = p;
    }
}

3.3、remove方法

remove(Object key)的作用是刪除key值對應的entry,該方法實現邏輯主要以HashMap為主,首先找到key值對應的entry,然後刪除該entry(修改鏈表的相應引用),查找過程跟get()方法類似,最後會調用 LinkedHashMap 中覆寫的方法,將其刪除!

/**HashMap 中實現*/
public V remove(Object key) {
    Node<K,V> e;
    return (e = removeNode(hash(key), key, null, false, true)) == null ?
        null : e.value;
}

final Node<K,V> removeNode(int hash, Object key, Object value,
                           boolean matchValue, boolean movable) {
    Node<K,V>[] tab; Node<K,V> p; int n, index;
    if ((tab = table) != null && (n = tab.length) > 0 &&
        (p = tab[index = (n - 1) & hash]) != null) {
        Node<K,V> node = null, e; K k; V v;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            node = p;
        else if ((e = p.next) != null) {
            if (p instanceof TreeNode) {...}
            else {
                // 遍歷單鏈表,尋找要刪除的節點,並賦值給 node 變量
                do {
                    if (e.hash == hash &&
                        ((k = e.key) == key ||
                         (key != null && key.equals(k)))) {
                        node = e;
                        break;
                    }
                    p = e;
                } while ((e = e.next) != null);
            }
        }
        if (node != null && (!matchValue || (v = node.value) == value ||
                             (value != null && value.equals(v)))) {
            if (node instanceof TreeNode) {...}
            // 將要刪除的節點從單鏈表中移除
            else if (node == p)
                tab[index] = node.next;
            else
                p.next = node.next;
            ++modCount;
            --size;
            afterNodeRemoval(node);    // 調用刪除回調方法進行後續操作
            return node;
        }
    }
    return null;
}

LinkedHashMap 中覆寫的 afterNodeRemoval 方法

void afterNodeRemoval(Node<K,V> e) { // unlink
    LinkedHashMap.Entry<K,V> p =
        (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    // 將 p 節點的前驅后後繼引用置空
    p.before = p.after = null;
    // b 為 null,表明 p 是頭節點
    if (b == null)
        head = a;
    else
        b.after = a;
    // a 為 null,表明 p 是尾節點
    if (a == null)
        tail = b;
    else
        a.before = b;
}

四、總結

LinkedHashMap 繼承自 HashMap,所有大部分功能特性基本相同,二者唯一的區別是 LinkedHashMap 在HashMap的基礎上,採用雙向鏈表(doubly-linked list)的形式將所有 entry 連接起來,這樣是為保證元素的迭代順序跟插入順序相同。

主體部分跟HashMap完全一樣,多了header指向雙向鏈表的頭部,tail指向雙向鏈表的尾部,默認雙向鏈表的迭代順序就是entry的插入順序。

五、參考

1、JDK1.7&JDK1.8 源碼
2、

作者:炸雞可樂
出處:

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

※評比前十大台北網頁設計台北網站設計公司知名案例作品心得分享

※智慧手機時代的來臨,RWD網頁設計已成為網頁設計推薦首選

台灣海運大陸貨務運送流程

兩岸物流進出口一站式服務