整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          產(chǎn)品經(jīng)理的技術(shù)腦:html是什么意思?

          文本標(biāo)記語言(HTML)是用于在 Internet 上顯示 Web 頁面的主要標(biāo)記語言。換句話說,網(wǎng)頁由 HTML 組成,用于通過 Web 瀏覽器顯示文本,圖像或其他資源

          使用標(biāo)記來描述文檔結(jié)構(gòu)和表現(xiàn)形式并通過瀏覽器進(jìn)行解析,然后把結(jié)果顯示在網(wǎng)頁上. 它是網(wǎng)頁構(gòu)成的基礎(chǔ),你見到的所有網(wǎng)頁都離不開HTML,所以學(xué)習(xí)HTML是基礎(chǔ)中的基礎(chǔ)。


          什么是HTML


          HTML是用來制作網(wǎng)頁的標(biāo)記語言

          HTML是Hypertext MarkupLanguage的英文縮寫, 即超文本標(biāo)記語言

          HTML語言是一種標(biāo)記語言,不需要編譯,直接由瀏 HTML語言是一種標(biāo)記語言,不需要編譯,直接由瀏覽器執(zhí)行

          HTML文件是一個(gè)文本文件,包含了一些HTML元素, HTML文件是一個(gè)文本文件,包含了一些HTML元素,標(biāo)簽等.

          HTML文件必須使用html或htm為文件名后綴

          HTML是大小寫不敏感的,HTML與html是一樣的


          HtmlCSS的關(guān)系


          學(xué)習(xí)web前端開發(fā)基礎(chǔ)技術(shù)需要掌握:HTML、CSS、JavaScript語言。下面我們就來了解下這三門技術(shù)都是用來實(shí)現(xiàn)什么的:


          1. HTML是網(wǎng)頁內(nèi)容的載體。內(nèi)容就是網(wǎng)頁制作者放在頁面上想要讓用戶瀏覽的信息,可以包含文字、圖片、視頻等。

          2. CSS樣式是表現(xiàn)(外觀控制)。就像網(wǎng)頁的外衣。比如,標(biāo)題字體、顏色變化,或?yàn)闃?biāo)題加入背景圖片、邊框等。所有這些用來改變內(nèi)容外觀的東西稱之為表現(xiàn)。

          3. JavaScript是用來實(shí)現(xiàn)網(wǎng)頁上的特效效果。如:鼠標(biāo)滑過彈出下拉菜單。或鼠標(biāo)滑過表格的背景顏色改變。還有焦點(diǎn)新聞(新聞圖片)的輪換。可以這么理解,有動(dòng)畫的,有交互的一般都是用JavaScript來實(shí)現(xiàn)的。

          HTML形象案例理解


          為了簡(jiǎn)化對(duì)復(fù)雜Internet的理解,暫時(shí)把復(fù)雜的Internet抽象成:向女生宿舍發(fā)送信號(hào)。

          為了能夠在斷網(wǎng)后繼續(xù)聯(lián)絡(luò)女神,我們買來了電池和開關(guān),然后拉了普通電線線到女神的寢室。女神把小燈泡接在了電線的兩端。

          這時(shí)只需要開閉開關(guān),就可以控制女神屋里的燈泡了。

          發(fā)送信號(hào)

          關(guān)閉著小燈泡1秒鐘,代表發(fā)送一個(gè)0。

          打開了小燈泡1秒鐘,代表發(fā)送一個(gè)1。

          此時(shí)可以向女神發(fā)送任意二進(jìn)制內(nèi)容了。

          發(fā)送文本

          我們只希望發(fā)送一個(gè)“Good Night”。所以必須想辦法對(duì)“Good Night”進(jìn)行編碼。

          'G','o','o','d'的ASCII編碼是:071,111,111,100,轉(zhuǎn)換成二進(jìn)制就是:0100 0001 0110 1111 0110 1111 0110 0100

          使用發(fā)送二進(jìn)制信號(hào)的方法發(fā)過去,女神需要自己解碼來閱讀出“Good”。


          發(fā)送富文本

          有一天,我們希望發(fā)送“I miss you”。

          為了表達(dá)心意,你希望加粗“you”,并使用紅色的字體發(fā)送“miss”,而這一根簡(jiǎn)陋的電線似乎很難理解“加粗”和“紅色”

          于是機(jī)智的我們發(fā)送了:I <red>miss</red> <b>you</b>

          同樣機(jī)智的女神理解了這件事情。


          你發(fā)明了一種語言

          我們很喜歡這種編碼格式,這是一種標(biāo)記語言,于是我們稱其為:TGML (To Girl Markup Language)

          平時(shí)你使用TGML來和你的女神通信,TGML可以非常好的解決富文本的傳輸問題。

          表白

          終于決定表白了,我們繪制了很美麗的心形圖片,還有兩個(gè)按鈕:接受、拒絕。

          兩個(gè)按鈕分別會(huì)鏈接到 "接受.tgml"和"拒絕.tgml"

          為了描述圖片,我們使用了<img src="pic">

          為了描述按鈕,我們使用了<a href="接受.tgml">

          現(xiàn)在發(fā)送給女神的內(nèi)容,已經(jīng)不只是帶格式的富文本,而是帶鏈接的富文本。

          于是在這個(gè)世界上,擁有了一種能夠描述超文本的語言,叫做TGML

          超文本

          描述超文本的方式有很多,例如:HTML,TGML,還有markdown。HTML的誕生是為了描述超文本。

          超文本的用途也很多,例如:描述一個(gè)網(wǎng)頁,或者描述一個(gè)Word文檔。HTML文件是超文本文件。但是超文本未必是HTML。

          Microsoft Word

          Microsoft Word是Office的一個(gè)組件。它同樣代表一個(gè)超文本資源。

          如果你解壓一個(gè)docx文件并仔細(xì)翻一翻,你能找到你剛才寫的作業(yè),是以HTML方式記載著。

          當(dāng)然,描述超文本還有markdown。所以你可以使用一些工具,比如pandoc,把markdown轉(zhuǎn)換成word。


          故事的結(jié)局

          女神的名字叫瀏覽器,我們的名字叫Web服務(wù)器,女神和我們中間的那根線叫HTTP。



          在前面

          今年國(guó)慶假期終于可以憋在家里了不用出門了,不用出去看后腦了,真的是一種享受。這么好的光陰怎么浪費(fèi),睡覺、吃飯、打豆豆這怎么可能(耍多了也煩),完全不符合我們程序員的作風(fēng),趕緊起來把文章寫完。

          這篇文章比較基礎(chǔ),在國(guó)慶期間的業(yè)余時(shí)間寫的,這幾天又完善了下,力求把更多的前端所涉及到的關(guān)于文件上傳的各種場(chǎng)景和應(yīng)用都涵蓋了,若有疏漏和問題還請(qǐng)留言斧正和補(bǔ)充。

          自測(cè)讀不讀

          以下是本文所涉及到的知識(shí)點(diǎn),break or continue ?

          • 文件上傳原理
          • 最原始的文件上傳
          • 使用 koa2 作為服務(wù)端寫一個(gè)文件上傳接口
          • 單文件上傳和上傳進(jìn)度
          • 多文件上傳和上傳進(jìn)度
          • 拖拽上傳
          • 剪貼板上傳
          • 大文件上傳之分片上傳
          • 大文件上傳之?dāng)帱c(diǎn)續(xù)傳
          • node 端文件上傳

          原理概述

          原理很簡(jiǎn)單,就是根據(jù) http 協(xié)議的規(guī)范和定義,完成請(qǐng)求消息體的封裝和消息體的解析,然后將二進(jìn)制內(nèi)容保存到文件。

          我們都知道如果要上傳一個(gè)文件,需要把 form 標(biāo)簽的enctype設(shè)置為multipart/form-data,同時(shí)method必須為post方法。

          那么multipart/form-data表示什么呢?

          multipart互聯(lián)網(wǎng)上的混合資源,就是資源由多種元素組成,form-data表示可以使用HTML Forms 和 POST 方法上傳文件,具體的定義可以參考RFC 7578。

          multipart/form-data 結(jié)構(gòu)

          看下 http 請(qǐng)求的消息體



          • 請(qǐng)求頭:

          Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryDCntfiXcSkPhS4PN 表示本次請(qǐng)求要上傳文件,其中boundary表示分隔符,如果要上傳多個(gè)表單項(xiàng),就要使用boundary分割,每個(gè)表單項(xiàng)由———XXX開始,以———XXX結(jié)尾。

          • 消息體- Form Data 部分

          每一個(gè)表單項(xiàng)又由Content-Type和Content-Disposition組成。

          Content-Disposition: form-data 為固定值,表示一個(gè)表單元素,name 表示表單元素的 名稱,回車換行后面就是name的值,如果是上傳文件就是文件的二進(jìn)制內(nèi)容。

          Content-Type:表示當(dāng)前的內(nèi)容的 MIME 類型,是圖片還是文本還是二進(jìn)制數(shù)據(jù)。

          解析

          客戶端發(fā)送請(qǐng)求到服務(wù)器后,服務(wù)器會(huì)收到請(qǐng)求的消息體,然后對(duì)消息體進(jìn)行解析,解析出哪是普通表單哪些是附件。

          可能大家馬上能想到通過正則或者字符串處理分割出內(nèi)容,不過這樣是行不通的,二進(jìn)制buffer轉(zhuǎn)化為string,對(duì)字符串進(jìn)行截取后,其索引和字符串是不一致的,所以結(jié)果就不會(huì)正確,除非上傳的就是字符串。

          不過一般情況下不需要自行解析,目前已經(jīng)有很成熟的三方庫可以使用。

          至于如何解析,這個(gè)也會(huì)占用很大篇幅,后面的文章在詳細(xì)說。

          最原始的文件上傳

          使用 form 表單上傳文件

          在 ie時(shí)代,如果實(shí)現(xiàn)一個(gè)無刷新的文件上傳那可是費(fèi)老勁了,大部分都是用 iframe 來實(shí)現(xiàn)局部刷新或者使用 flash 插件來搞定,在那個(gè)時(shí)代 ie 就是最好用的瀏覽器(別無選擇)。

          DEMO



          這種方式上傳文件,不需要 js ,而且沒有兼容問題,所有瀏覽器都支持,就是體驗(yàn)很差,導(dǎo)致頁面刷新,頁面其他數(shù)據(jù)丟失。

          HTML

           <form method="post" action="http://localhost:8100" enctype="multipart/form-data">
          
                  選擇文件:
                      <input type="file" name="f1"/> input 必須設(shè)置 name 屬性,否則數(shù)據(jù)無法發(fā)送<br/>
          <br/>
                      標(biāo)題:<input type="text" name="title"/><br/><br/><br/>
          
                  <button type="submit" id="btn-0">上 傳</button>
          
          </form>
          
          復(fù)制代碼

          文件上傳接口

          服務(wù)端文件的保存基于現(xiàn)有的庫koa-body結(jié)合 koa2實(shí)現(xiàn)服務(wù)端文件的保存和數(shù)據(jù)的返回。

          在項(xiàng)目開發(fā)中,文件上傳本身和業(yè)務(wù)無關(guān),代碼基本上都可通用。

          在這里我們使用koa-body庫來實(shí)現(xiàn)解析和文件的保存。

          koa-body 會(huì)自動(dòng)保存文件到系統(tǒng)臨時(shí)目錄下,也可以指定保存的文件路徑。



          然后在后續(xù)中間件內(nèi)得到已保存的文件的信息,再做二次處理。

          • ctx.request.files.f1 得到文件信息,f1為input file 標(biāo)簽的 name
          • 獲得文件的擴(kuò)展名,重命名文件

          NODE

          /**
           * 服務(wù)入口
           */
          var http = require('http');
          var koaStatic = require('koa-static');
          var path = require('path');
          var koaBody = require('koa-body');//文件保存庫
          var fs = require('fs');
          var Koa = require('koa2');
          
          var app = new Koa();
          var port = process.env.PORT || '8100';
          
          var uploadHost= `http://localhost:${port}/uploads/`;
          
          app.use(koaBody({
              formidable: {
                  //設(shè)置文件的默認(rèn)保存目錄,不設(shè)置則保存在系統(tǒng)臨時(shí)目錄下  os
                  uploadDir: path.resolve(__dirname, '../static/uploads')
              },
              multipart: true // 開啟文件上傳,默認(rèn)是關(guān)閉
          }));
          
          //開啟靜態(tài)文件訪問
          app.use(koaStatic(
              path.resolve(__dirname, '../static') 
          ));
          
          //文件二次處理,修改名稱
          app.use((ctx) => {
              var file = ctx.request.files.f1;//得道文件對(duì)象
              var path = file.path;
              var fname = file.name;//原文件名稱
              var nextPath = path+fname;
              if(file.size>0 && path){
                  //得到擴(kuò)展名
                  var extArr = fname.split('.');
                  var ext = extArr[extArr.length-1];
                  var nextPath = path+'.'+ext;
                  //重命名文件
                  fs.renameSync(path, nextPath);
              }
              //以 json 形式輸出上傳文件地址
              ctx.body = `{
                  "fileUrl":"${uploadHost}${nextPath.slice(nextPath.lastIndexOf('/')+1)}"
              }`;
          });
          
          /**
           * http server
           */
          var server = http.createServer(app.callback());
          server.listen(port);
          console.log('demo1 server start ......   ');
          復(fù)制代碼

          CODE

          https://github.com/Bigerfe/fe-learn-code/

          年來,前端技術(shù)日新月異,前端已經(jīng)不僅僅是網(wǎng)頁,更多的開始由狹義向廣義發(fā)展。

          先后涌現(xiàn)出了具備后端能力的node,具備移動(dòng)開發(fā)能力的react native,具備游戲渲染能力的cocos2d-js,以及iOS上的熱修復(fù)技術(shù)JSPatch等等新技術(shù)。

          咋一看,幾乎各個(gè)端都被JavaScript攻陷,大有一統(tǒng)江湖之勢(shì)。

          究竟,JavaScript如何做到上天入地?zé)o所不能?JavaScript真的能一統(tǒng)江湖嗎?

          亂世出英雄:JavaScript的誕生故事要從JavaScript的由來說起。

          高能瞎扯淡版,正經(jīng)臉的同學(xué)可以忽略

          有人的地方就有江湖,有江湖的地方就有紛爭(zhēng)。

          故事要從當(dāng)年的瀏覽器之戰(zhàn)說起。

          時(shí)間回到1994年,

          (→ 那時(shí)候我還是個(gè)寶寶~ #天真臉#)

          景兄弟橫空出世,并自帶神器網(wǎng)景導(dǎo)航,戰(zhàn)斗力爆表,勢(shì)如劈竹,瞬時(shí)間威震天下。

          一出世就武裝到牙齒,武力值這么高還自帶兵器,這個(gè)科學(xué)嗎?

          港真,我也覺得不科學(xué),也許跟熊孩子哪吒、女漢子雅典娜是一個(gè)品種吧?

          這一切北方的老前輩微軟大濕,都看在眼里,不甘天下盡歸景兄弟這個(gè)初出茅廬的毛孩子,大濕積淀多年,潛心修煉一年,終于帶著大殺器IE 1.0出關(guān)了,誓于景兄弟爭(zhēng)個(gè)高低。

          自此景兄弟的網(wǎng)景導(dǎo)航 VS 微軟大濕的IE 的軍備戰(zhàn)爭(zhēng)開始。

          景兄弟仔細(xì)掂量,微軟大濕財(cái)大氣粗,內(nèi)功深厚,臣妾實(shí)在是辦不到啊啊啊啊啊啊。

          景兄弟緊急召集門人商議對(duì)策,有一門人曰:”以我們微薄之力硬磕,是萬萬使不得的。如今我們,一是宜施行合縱之策,抱大腿,組成聯(lián)盟!二是避其鋒芒,出奇招致勝。“

          于是景兄弟依照此策略,一方面找到了當(dāng)時(shí)德高為重的另一位前輩SUN,組成了開發(fā)者聯(lián)盟。

          (微軟大濕:握草,聯(lián)盟都粗來了,那我是不是得搞個(gè)部落?)

          另一方面,景兄弟找到了鍛造大師布蘭登,請(qǐng)布大師幫忙升級(jí)兵器網(wǎng)景導(dǎo)航,大師就是大師,不費(fèi)吹灰之力就完成了強(qiáng)化升級(jí),然而布大師突發(fā)奇想,本來這是近距離攻擊兵器,要是有多一個(gè)遠(yuǎn)距離攻擊的能力那豈不是更好?Just do it. 想罷大師就加了一個(gè)遠(yuǎn)距離攻擊的feature。于是有了自帶遠(yuǎn)距離攻擊能力的網(wǎng)景導(dǎo)航2.0。景兄弟一看這么流弊心里甚是歡喜,不過遠(yuǎn)距離攻擊的技能叫做LiveScript,感覺不是特別Fashion。特然想到這不是跟SUN前輩聯(lián)盟嘛,SUN家的Java正是獨(dú)霸武林之時(shí)。不如把名字改成跟Java有關(guān),蹭一把東風(fēng),蹭點(diǎn)光環(huán)。一拍腦袋,JavaScript!!!眾門人一聽:”好好好,JavaScript 流弊炫酷吊炸天!“

          果然第一節(jié)下半場(chǎng),景兄弟攜強(qiáng)化過的網(wǎng)景導(dǎo)航2.0 戰(zhàn)個(gè)痛快,那是杠杠的!人家一問,你咋還能遠(yuǎn)程攻擊,你這個(gè)遠(yuǎn)程攻擊用的是啥?答曰:JavaScript。“JavaScript,一定是跟SUN家Java是一個(gè)系列產(chǎn)品,一定很流弊!”#光環(huán)加成,各種膜拜臉#

          微軟大濕虧了一場(chǎng),痛定思痛,也要搞遠(yuǎn)程攻擊功能,果然不久,就祭出了同樣帶有遠(yuǎn)程攻擊能力的IE 3.0,鑒于景兄弟的遠(yuǎn)程攻擊叫做JavaScript,J開頭的感覺應(yīng)該比較流弊,所以微軟大濕的叫做JScript。

          然后戰(zhàn)爭(zhēng)就從地面貼身肉搏戰(zhàn),開始逐步升級(jí)到了遠(yuǎn)距離核戰(zhàn)爭(zhēng)。

          正所謂,城門失火,殃及池魚。這么打下去苦逼的是搬磚的頁面仔,就是我這種,到處都是雷區(qū),無處下腳。

          最后到了1997年,“聯(lián)合國(guó)安理會(huì)秘書長(zhǎng)”艾瑪(ECMA)出來調(diào)停,多方簽署了“核不擴(kuò)散條約”,約束各種遠(yuǎn)程攻擊武器的使用,這才走上了正軌。

          1995年SUN開發(fā)了Java技術(shù),這是第一個(gè)通用軟件平臺(tái)。Java擁有跨平臺(tái)、面向?qū)ο蟆⒎盒途幊痰奶匦裕瑥V泛應(yīng)用于企業(yè)級(jí)Web應(yīng)用開發(fā)和移動(dòng)應(yīng)用開發(fā)。Java也伴隨著互聯(lián)網(wǎng)的迅猛發(fā)展而發(fā)展,逐漸成為重要的網(wǎng)絡(luò)編程語言。名噪一時(shí)。

          1994年Netscape公司成立,并推出了自己的瀏覽器的免費(fèi)版本 Netscape Navigator,很快就占有了瀏覽器市場(chǎng)。到了 1995 年,微軟公司開始加入,并很快發(fā)布了自己的 Internet Explorer 1.0。

          1995年,當(dāng)時(shí)在Netscape就職的Brendan Eich(布蘭登·艾克),正為Netscape Navigator 2.0瀏覽器開發(fā)的一門名為L(zhǎng)iveScript的腳本語言,后來Netscape與Sun Microsystems組成的開發(fā)聯(lián)盟,為了讓這門語言搭上Java這個(gè)編程語言“熱詞”,將其臨時(shí)改名為“JavaScript”,日后這成為大眾對(duì)這門語言有諸多誤解的原因之一。

          JavaScript最初受Java啟發(fā)而開始設(shè)計(jì)的,目的之一就是“看上去像Java”,因此語法上有類似之處,一些名稱和命名規(guī)范也借自Java。但JavaScript的主要設(shè)計(jì)原則源自Self和Scheme。JavaScript與Java名稱上的近似,是當(dāng)時(shí)Netscape為了營(yíng)銷考慮與SUN達(dá)成協(xié)議的結(jié)果。

          ==> 所以,JavaScript和Java其實(shí)沒有半毛錢關(guān)系。

          JavaScript推出后在瀏覽器上大獲成功,微軟在不久后就為Internet Explorer 3.0瀏覽器推出了JScript,以與處于市場(chǎng)領(lǐng)導(dǎo)地位的Netscape產(chǎn)品同臺(tái)競(jìng)爭(zhēng)。JScript也是一種JavaScript實(shí)現(xiàn),這兩個(gè)

          JavaScript語言版本在瀏覽器端共存意味著語言標(biāo)準(zhǔn)化的缺失,對(duì)這門語言進(jìn)行標(biāo)準(zhǔn)化被提上了日程,在1997年,由Netscape、SUN、微軟、寶藍(lán)等公司組織及個(gè)人組成的技術(shù)委員會(huì)在ECMA(歐洲計(jì)算機(jī)制造商協(xié)會(huì))確定定義了一種名叫ECMAScript的新腳本語言標(biāo)準(zhǔn),規(guī)范名為ECMA-262。JavaScript成為了ECMAScript的實(shí)現(xiàn)之一。ECMA-262 第五版,即是ES5。

          ==> ECMA-262,包括ES5, ES6等是一個(gè)標(biāo)準(zhǔn),JavaScript是ECMAScript的一個(gè)實(shí)現(xiàn)。

          完整的JavaScript實(shí)現(xiàn)應(yīng)該包含三個(gè)部分:

          在網(wǎng)景導(dǎo)航2.0和IE 3.0出現(xiàn)之后的幾年間,網(wǎng)景和微軟公司不停的發(fā)布新版本的瀏覽器,支持更多的新功能。自此拉開了瀏覽器之戰(zhàn)的序幕。這場(chǎng)瀏覽器之戰(zhàn)到現(xiàn)在還在繼續(xù),以下一張圖看清楚過程。

          從瀏覽器之戰(zhàn)可以看出,各家瀏覽器比拼的大致兩個(gè)方面視覺體驗(yàn)(渲染排版)和速度(腳本運(yùn)行)。

          ==> 所以一個(gè)完整的瀏覽器組成,至少包含兩個(gè)部分:

          補(bǔ)充一個(gè)市面常見瀏覽器的內(nèi)核和JavaScript引擎搭配:

          其他JavaScript引擎,Rhino,由Mozilla基金會(huì)管理,開放源代碼,完全以Java編寫,可以看做SpiderMonkey的Java版。

          注意:webkit不單單只是一個(gè)排版引擎,webkit = 排版引擎 + JavaScript引擎。

          ==> 所以,JavaScript是動(dòng)態(tài)語言,它的運(yùn)行都是基于JavaScript引擎,引擎大都是由靜態(tài)語言實(shí)現(xiàn)C++、Java、and so on。JavaScript的能力也是由引擎賦予。不管是瀏覽器環(huán)境中是window,亦或是node環(huán)境中的process,均是由引擎提供。

          (番外:Mozilla的人不知道為啥特別喜歡猴子,經(jīng)常以猴子命名技術(shù),所以看到帶Monkey的,十有八九估計(jì)是他們搞的。)

          諾曼底登陸:JavaScript Binding/Bridge 橋接技術(shù)

          在瀏覽器環(huán)境中,DOM、BOM、window對(duì)象、setTimeout/setInterval,alert,console等方法均不是JavaScript自身具備的能力,而是瀏覽器native實(shí)現(xiàn),然后通過JavaScript引擎注入到JS運(yùn)行的全局上下文中,供JS使用。

          鑒別方式,在調(diào)試器console中打出來,帶有[native code]的即是:

          講道理:

          1. JavaScript運(yùn)行 → 依賴于JavaScript引擎 ← 瀏覽器集成了JavaScript引擎,同時(shí)通過JavaScript引擎注入native代碼工JS腳本使用

          2. 發(fā)散一下思維,只要有JavaScript引擎,就能運(yùn)行JS腳本,不管有沒有瀏覽器!只是缺少瀏覽器提供的alert,window等方法。

          3. 既然瀏覽器可以往JavaScript引擎中注入代碼,賦予JS腳本在網(wǎng)頁中特殊的能力,同理我們可以自己集成JavaScript引擎,自己定義自己的方法往JavaScript引擎中注入,賦予JS更多更強(qiáng)的自定義能力!

            注入的關(guān)鍵是:值類型相互對(duì)應(yīng),Obj映射class的一個(gè)實(shí)例,function映射一個(gè)句柄或者引用

          JavaScript數(shù)值型中的坑

          JavaScript內(nèi)部,所有數(shù)字都是以64位浮點(diǎn)數(shù)形式儲(chǔ)存,即使整數(shù)也是如此

          這就是說,在JavaScript語言的底層,根本沒有整數(shù),所有數(shù)字都是小數(shù)(64位浮點(diǎn)數(shù))。容易造成混淆的是,某些運(yùn)算只有整數(shù)才能完成,此時(shí)JavaScript會(huì)自動(dòng)把64位浮點(diǎn)數(shù),轉(zhuǎn)成32位整數(shù),然后再進(jìn)行運(yùn)算。由于浮點(diǎn)數(shù)不是精確的值,所以涉及小數(shù)的比較和運(yùn)算要特別小心。盡量避免使用JavaScript做精準(zhǔn)計(jì)算和密集計(jì)算。

          根據(jù)國(guó)際標(biāo)準(zhǔn)IEEE 754,JavaScript浮點(diǎn)數(shù)的64個(gè)二進(jìn)制位,從最左邊開始,是這樣組成的。

          • 第1位:符號(hào)位,0表示正數(shù),1表示負(fù)數(shù)

          • 第2位到第12位:儲(chǔ)存指數(shù)部分

          • 第13位到第64位:儲(chǔ)存小數(shù)部分(即有效數(shù)字)

            符號(hào)位決定了一個(gè)數(shù)的正負(fù),指數(shù)部分決定了數(shù)值的大小,小數(shù)部分決定了數(shù)值的精度。

            IEEE 754規(guī)定,有效數(shù)字第一位默認(rèn)總是1,不保存在64位浮點(diǎn)數(shù)之中。也就是說,有效數(shù)字總是1.xx…xx的形式,其中xx..xx的部分保存在64位浮點(diǎn)數(shù)之中,最長(zhǎng)可能為52位。因此,JavaScript提供的有效數(shù)字最長(zhǎng)為53個(gè)二進(jìn)制位(64位浮點(diǎn)的后52位+有效數(shù)字第一位的1)。

          內(nèi)部表現(xiàn)公式:(-1)^符號(hào)位 1.xx…xx 2^指數(shù)位

          精度最多只能到53個(gè)二進(jìn)制位,這意味著,絕對(duì)值小于2的53次方的整數(shù),即-(253-1)到253-1,都可以精確表示。

          而大部分的后端語言,C++、Java、Python等的long型都是可以支持到64位,因此long型數(shù)據(jù)從后端語言傳給JavaScript會(huì)發(fā)生低位截?cái)?/strong>。遇到這種情況一般使用String處理,如需要在JavaScript中做long型計(jì)算,需要自行實(shí)現(xiàn)計(jì)算器。

          有了自行往JavaScript引擎中注入的想法,接下來就是分析可行性。

          大部分是JavaScript引擎是使用C++編寫,如果自己的程序使用的是C++可以很方便的進(jìn)行注入,如果是OC,可以使用OC和C++混編的形式。

          其他語言怎么破?

          要在一門靜態(tài)語言上與動(dòng)態(tài)語言JavaScript相互調(diào)用,最便捷的方式是找到一個(gè)這門語言實(shí)現(xiàn)的JavaScript引擎(開源),直接進(jìn)行集成,注入。如果沒有,則需要使用多一層橋接,把這門語言的接口暴露給C++,再由C++實(shí)現(xiàn)的JavaScript引擎將接口注入供JavaScript使用。

          服務(wù)端集成思路&實(shí)踐:

          nodeJS中的橋接

          我們都知道nodeJS,但是nodeJS的運(yùn)行依賴于Google的V8 引擎,V8是C++實(shí)現(xiàn),底層使用C++實(shí)現(xiàn)底層功能,比如網(wǎng)絡(luò),數(shù)據(jù)庫IO,對(duì)外暴露一個(gè)構(gòu)造器接口注入到上下文中,注意此處暴露的只是一個(gè)構(gòu)造器接口而不是一個(gè)創(chuàng)建完的實(shí)例。然后實(shí)現(xiàn)了一個(gè)require的hook函數(shù)。當(dāng)使用require加載一個(gè)JS模塊時(shí),跟網(wǎng)頁中使用AMD 的require并無異樣,當(dāng)使用require加載系統(tǒng)庫,既是C++的模塊時(shí),會(huì)調(diào)用暴露出來的構(gòu)造器接口,得到一個(gè)實(shí)例對(duì)象。不管是裝載JS模塊還是裝載C++模塊,得到的都可以看做是一個(gè)Module Object,node會(huì)將裝載完的模塊緩存到binding_cache中,下次在別處的代碼中使用require裝載模塊時(shí),就會(huì)先去binding_cache中查找,如果找到了則返回該module object,如果沒找到再執(zhí)行上面的裝載流程。

          這就是node的基本原理:C++封裝底層操作,通過V8注入,使得JS腳本有網(wǎng)絡(luò)和IO能力

          基于Spring的橋接

          以上說到的幾個(gè)都是C++層面的應(yīng)用,那么經(jīng)典的Java怎么玩?是不是Java就必須是靜態(tài)語言的玩法,沒有辦法像C++之類的,可以使用JS的動(dòng)態(tài)特性?

          當(dāng)然不是。這個(gè)時(shí)候,我們需要說起前面介紹過的一個(gè)JS引擎 Rhino,Rhino是完全由Java編寫,可想而知,Rhino幾乎就是為Java應(yīng)用而生的。

          用法是這樣:

          1. 首先在我們的Java應(yīng)用中集成Rhino;

          2. 所有的IO操作,網(wǎng)絡(luò)操作等,都封裝成service,并提供增刪改查,setter && getter等多種方法

          3. 通過spring,把這些service bean注入到Rhino中;

          4. 把業(yè)務(wù)邏輯寫到JS代碼中,JS代碼調(diào)用多個(gè)已注入的Java service處理業(yè)務(wù)邏輯,拼裝數(shù)據(jù)返回!

          好處:修改業(yè)務(wù)邏輯不需要修改Java代碼,也就是不需要重新編譯和部署,只需要刷新下跑在Rhino中的JS代碼即可。以往Java應(yīng)用的一個(gè)痛點(diǎn)是部署,需要重新編譯,打包,部署重啟服務(wù)器,現(xiàn)在以這種形式開發(fā),可以達(dá)到服務(wù)端的熱更新和熱部署。既可以享有Java服務(wù)的穩(wěn)定性和可靠性,又可以享有JS的靈活性。

          這種技術(shù)和用法在差不多十年前就有過,前EMC的工程師基于EMC著名的商業(yè)產(chǎn)品Documentum,設(shè)計(jì)了一套Java開源的中小企業(yè)CMS系統(tǒng)Alfresco,在該系統(tǒng)中實(shí)現(xiàn)了這種技術(shù),這種技術(shù)基于spring,叫做spring-surf,做了一個(gè)膠水層。可以看做小十年前的node吧。

          Demo,使用spring-surf框架的系統(tǒng)中一個(gè)webscript模塊

          1. categorynode.get.xml定義URL攔截器和權(quán)限控制;

          2. .get指明是處理GET請(qǐng)求,RESTful;

          3. 在categorynode.get.js中調(diào)用已注入的Java Bean處理業(yè)務(wù)邏輯;

          4. 若為網(wǎng)頁請(qǐng)求返回.html.ftl,若為Ajax,返回.json.ftl;

          (此處配套使用的是FreeMarker模板引擎)

          ==> categorynode.get.desc.xml

          ==> categorynode.get.js

          ==> categorynode.get.html.ftl

          ==> categorynode.get.json.ftl

          移動(dòng)端集成思路&實(shí)踐:

          React Native中的橋接

          React Native目前也是異常火爆,RN程序的運(yùn)行依賴于Facebook的RN框架。在iOS、Android的模擬器或是真機(jī)上,React Native使用的是JavaScriptCore引擎,也就是Safari所使用的JavaScript引擎。但是在iOS上JavaScriptCore并沒有使用即時(shí)編譯技術(shù)(JIT),因?yàn)樵趇OS中應(yīng)用無權(quán)擁有可寫可執(zhí)行的內(nèi)存頁(因而無法動(dòng)態(tài)生成代碼),在安卓上,理論上是可以使用的。JavaScriptCore引擎也是使用C++編寫,在iOS和安卓中,JavaScriptCore都做了一層封裝,可以無須關(guān)心引擎和系統(tǒng)橋接的那一層。iOS/Android系統(tǒng)通過JavaScriptCore引擎將定制好的各種原生組件注入,如:listview,text等。

          Cocos2d-JS中的橋接

          cocos2dx是游戲開發(fā)中非常常用的游戲渲染引擎,有一系列的產(chǎn)品,如:cocos2dx(C++),cocos2d-lua(lua), cocos2d-js(JavaScript)等多個(gè)產(chǎn)品。其中最新退出的是cocos2dx的JS版本的cocos2d-js,編寫游戲渲染特效代碼相比于C++和lua非常方便。對(duì)于做需要經(jīng)常更新的渲染場(chǎng)景,C++是靜態(tài)語言,每次修改都需要重新編譯才能運(yùn)行,顯然是不合適的。自然也就想到了腳本語言,lua和js,兩者有些類似,都是動(dòng)態(tài)語言,只需要集成一個(gè)運(yùn)行引擎,提供一個(gè)運(yùn)行的容器即可運(yùn)行,同時(shí)通過引擎注入底層方法供腳本調(diào)用即可。lua好處是精簡(jiǎn),語法精簡(jiǎn),引擎頁很小很精簡(jiǎn),所以不可避免的代碼量會(huì)比js多,同時(shí)學(xué)習(xí)成本比較高。js的好處是有ECMAScrtpt的核心,語法比較豐富,同時(shí)有支持一些高級(jí)屬性。在cocos2d-js中,cocos2dx(C++)集成了SpiderMonkey(C++)作為JS運(yùn)行引擎,中間做了一個(gè)膠水層既是JS Binding,通過引擎注入了一個(gè)cc的全局對(duì)象,映射的是底層C++的一個(gè)單例C++實(shí)例。表面上寫的是JS代碼,實(shí)際上操作的是底層的C++。cocos2d-js是代碼可以運(yùn)行在多種環(huán)境中,當(dāng)運(yùn)行的網(wǎng)頁環(huán)境中時(shí),使用的是cocos2d-html5引擎,底層操作的是canvas;當(dāng)運(yùn)行在客戶端上時(shí),使用的是cocos2dx引擎,底層操作的是C++,再由C++去操控openGL做繪制和渲染。提供相同的API,對(duì)開發(fā)者幾乎是透明無差異的,開發(fā)者只需要關(guān)注實(shí)現(xiàn)效果即可。達(dá)到一套代碼,多端運(yùn)行(網(wǎng)頁端,客戶端)。

          JSPatch技術(shù)中的橋接

          JSPatch是目前比較流行的iOS上的熱修復(fù)技術(shù),JSPatch 能做到通過 JS 調(diào)用和改寫 OC 方法最根本的原因是 Objective-C 是動(dòng)態(tài)語言,OC 上所有方法的調(diào)用/類的生成都通過 Objective-C Runtime 在運(yùn)行時(shí)進(jìn)行,我們可以通過類名/方法名反射得到相應(yīng)的類和方法。JSPatch 的基本原理就是:JS 傳遞字符串給 OC,OC 通過 Runtime 接口調(diào)用和替換 OC 方法。

          關(guān)鍵技術(shù)之一是 JS 和 OC 之間的消息互傳。JSPatch里包含了,一個(gè)JS引擎JavaScriptCore(Safari,React Native用的同款)。用到了 JavaScriptCore 的接口,OC 端在啟動(dòng) JSPatch 引擎時(shí)會(huì)創(chuàng)建一個(gè) JSContext 實(shí)例,JSContext 是 JS 代碼的執(zhí)行環(huán)境,可以給 JSContext 添加方法,JS 就可以直接調(diào)用這個(gè)方法。本質(zhì)上就是通過JavaScriptCore引擎注入,暴露OC的方法供JS調(diào)用來實(shí)現(xiàn)動(dòng)態(tài)修改OC的反射。

          Demo,iOS熱更新,熱修復(fù):

          1. 集成JavaScriptCore引擎;

          2. 通過引擎,橋接JS和OC;

          3. 通過JS修改OC反射。

          詳細(xì)的JSPatch技術(shù)介紹請(qǐng)移步:https://github.com/bang590/JSPatch/wiki

          關(guān)于JavaScript引擎:

          在iOS 或 android 上能夠運(yùn)行的JavaScript 引擎有4個(gè):JavaScriptCore,SpiderMonkey,V8,Rhino。下面這個(gè)表格展示各個(gè)引擎在iOS 和 Android 的兼容性。

          因?yàn)閕OS平臺(tái)不支持JIT即時(shí)編譯,而V8只有JIT模式,所以V8無法在iOS平臺(tái)使用(越獄設(shè)備除外,想體驗(yàn)iOS JIT的同學(xué)可以自行越獄)。

          所以,目前可以做到橫跨iOS和Android雙平臺(tái)的JS引擎,只有兩款,即是SpiderMonkey和JavaScriptCore。

          JavaScript引擎會(huì)受很多東西影響,比如交叉編譯器的版本、引擎的版本和操作系統(tǒng)的種類等。

          至于如何選擇,可以參考:《Part I: How to Choose a JavaScript Engine for iOS and Android Development》

          至此,JavaScript從立足于前端,到征戰(zhàn)全端的逆襲之路,可以總結(jié)為“攜引擎以令天下”。

          不足之處,還請(qǐng)各位看官輕拍~

          參考文章:

          bang590/JSPatch中問參考文檔

          Cocos2d-JS | Cocos2d-x官方參考文檔

          Alfresco官方參考文檔

          《Browser Wars: The End or Just the Beginning?》

          《Part I: How to Choose a JavaScript Engine for iOS and Android Development》

          《React Native 從入門到源碼》


          主站蜘蛛池模板: 国产不卡视频一区二区三区| 亚洲av无码一区二区三区观看| 日本免费精品一区二区三区| 久久综合亚洲色一区二区三区| 精品国产一区二区22| 国模极品一区二区三区| 乱码精品一区二区三区| 亚洲日本一区二区三区在线| 久久精品无码一区二区三区日韩 | 变态拳头交视频一区二区| 精品一区二区91| 国产精品成人一区无码| 伊人无码精品久久一区二区| 亚洲AV成人一区二区三区在线看| 麻豆一区二区99久久久久| 文中字幕一区二区三区视频播放| 亚洲色精品vr一区二区三区| 日韩综合无码一区二区| 99精品国产高清一区二区三区 | 精品人妻一区二区三区浪潮在线| 无码人妻精品一区二区三区99仓本 | 国精品无码一区二区三区左线| 激情内射日本一区二区三区| 亚洲色精品vr一区二区三区| 一区二区三区日韩精品| 老熟女高潮一区二区三区| 人妻精品无码一区二区三区 | 精品福利一区二区三区精品国产第一国产综合精品 | 精品福利一区3d动漫| 日韩精品一区二区三区视频| 中文字幕一区在线播放| 消息称老熟妇乱视频一区二区| 亚洲一区二区三区电影| 亚洲国产成人久久一区二区三区| 无码丰满熟妇浪潮一区二区AV| 相泽南亚洲一区二区在线播放| 精品乱码一区内射人妻无码| 国产激情一区二区三区成人91| 久久亚洲综合色一区二区三区| 性色A码一区二区三区天美传媒| 亚洲狠狠狠一区二区三区|