<dfn id="hx5t3"><strike id="hx5t3"><em id="hx5t3"></em></strike></dfn>

    <thead id="hx5t3"></thead><nobr id="hx5t3"><font id="hx5t3"><rp id="hx5t3"></rp></font></nobr>

    <listing id="hx5t3"></listing>

    <var id="hx5t3"></var>
    <big id="hx5t3"></big>

      
      

      <output id="hx5t3"><ruby id="hx5t3"></ruby></output>
      <menuitem id="hx5t3"><dfn id="hx5t3"></dfn></menuitem>

      <big id="hx5t3"></big>

        mcfog

        mcfog 查看完整檔案

        上海編輯  |  填寫畢業院校  |  填寫所在公司/組織 about.mcfog.wang 編輯
        編輯

        bWNmb2d3I2dtYWls

        個人動態

        mcfog 發布了文章 · 2020-11-09

        “微服務”技術另一個可能更合適的名字

        引言

        這兩天夜觀天象準備分享,重新對服務化、微服務等技術的來龍去脈做了一些思考和總結,當然網上早有一百篇或者一萬篇不同的文章來解釋和描述服務化是什么微服務是什么,微服務和服務化的區別是什么,我也看過其中一二。我從來不打算說重復的東西,說的也沒有大師好。但微服務這個東西既不像【我不想提及的網絡熱詞】技術那樣基本上啥都不是就是騙騙外行,又不像【另一個熱點技術詞匯】那樣“大家都理解關于那個東西大家的理解不一致”,冷靜下來思考,一種可能性就是這個名字起的不好沒有直擊本質,導致一些誤解,這兩天突然想通一些東西,這里和各位探討一下。

        服務和微

        首先我們來扣一下字眼,服務(service)是什么? 搜中文大概是這的【履行職務,為他人做事,并使他人從中受益的活動】,英文的含義1大概是【the action of helping or doing work for someone.】,意思其實是一樣的,serve的名詞,從技術角度看有點似是而非。英文含義2比較貼近我們技術角度說的服務【a system supplying a public need such as transport, communications, or utilities such as electricity and water.】雖然對應中文比較明顯是”公共事業“,但還是基本命中”服務化“這件事情的核心點:1、獨立系統;2、公共需求。

        然后看一下“微”(micro-),這個詞字面意思沒有什么誤解,但放到微服務里要解讀它就有點困難了,不如說有很多正確答案,可能有:

        • 單一職責(指責小,內聚)
        • 單進程,容器化等(體量輕)

        等等,問題在于,這些特性、方向、指導原則,其實和巨石架構到服務化的方向是一模一樣的。一個東西如果只是比原來的一個東西程度更甚,只是量變,那它是沒有資格被單獨討論的:高鐵也是鐵路,高鐵再快,就算是比飛機還快的磁浮,也還是鐵路,也還是火車站,也還是軌道交通系統。飛機,就算是原始飛機飛得再慢,問題再多,和火車也是不一樣的東西,因為那是質變。

        我不太同意微服務只是原來服務化方向上的量變,所以不太認可微服務這個名字,就好像把飛機叫超快火車那樣,快是飛機比火車的優點,但飛機的本質是飛,不是快。

        微服務的本質

        我們來回想一下談到“微服務”的時候我們一般談論什么?服務治理、服務網格(service mesh)、容器編排等等,這些東西其實并不和“微”直接相關,但微服務這個名字卻一直被大家用下來,我也并沒有發現有人對這個名字有不滿(一定有,可是我不知道),可能是因為這些技術解決的是服務化落地以后,單個服務進一步腫脹,試圖進一步拆分(微)的時候,遇到的實際困難。

        解決火車提速的實際困難有兩條路:發明更快的火車或者發明飛機,那么是什么東西讓我們認為“微服務”這個東西并不是高鐵,而是飛機,對比服務化火車是具備革命性的變化的呢?這個問題的答案(能飛)最終能夠成為微服務技術的更好的名字(飛機)。

        微服務技術的掌上明珠Istio一直在迅猛發展,最近的一條消息是Istio重構了它的控制平面,將原本控制平面內部的“微服務”架構重構為單體架構,原本control plane的多個組件Pilot, Galley, Citadel等被合并為一個istiod程序。這條消息引起了一些關于微服務vs巨石的討論,但無論如何,不會有人認為istio成為一個單體服務后,istio架構就不是一個微服務架構了,這也應證了我的思考,微服務的本質不是微。那么讓istio得以呈現它微服務本質的特點是什么?

        元服務 meta-service

        Istio本身原本是微服務,即使它變成了巨石架構,它仍然是一個服務,這個服務和非微服務架構里的各種服務還是有本質區別:它服務的“公共需求”,既不是業務需求(業務服務),也不是技術實現的需求(基礎服務如DB、隊列),而是“服務化”本身,istio是為服務化服務的服務。寫服務解決服務化過程中遇到的瓶頸和挑戰,這才是”微服務架構“區別于服務化架構的本質,這并不因istio內部組件融合成巨石架構而動搖,這才是”微服務“技術的本質,所以它的名字應當是元服務。(這里開始我把微服務統一叫元服務)

        元(meta-)這個前綴的含義是自引用、關于X的X:關于數據的數據叫元數據,寫程序操作程序叫元編程,那么,解決服務化問題的服務,自然應當被稱為元服務,我們討論元服務時,幾乎不討論某個業務服務是否micro或者如何把它做micro,而是討論為了把服務拆分好,需要實現某某特性,因此引進或者研發某某服務解決這個問題。

        服務化架構為什么遇到困境?因為服務化架構在解決自身問題的時候,并沒有用到服務化的思想。元服務更全面地應用了服務化思想,從而使得它和服務化架構有了本質的區別,插上翅膀成為飛機,從而被大家討論、實踐和學習。

        后記

        有了這個思考以后,我第一時間搜索了meta-service,并沒有找到類似的文章,和技術相關的meta-service一般是metadata-service,也就是元數據服務,中文的元服務更沒有什么東西,于是有了這篇文章。


        轉自本人博客

        查看原文

        贊 0 收藏 0 評論 0

        mcfog 發布了文章 · 2019-06-30

        雖然并沒有貢獻者出現,但我還是堅持把我的PHP框架堆到完成度很高的程度了

        如果一個框架能用很少的業務代碼實現特別多的功能,那么其實就是這個框架內置了大量的慣例,當這些慣例不符合項目預期的時候,如何添加代碼精確地改變對應的慣例,而不搞砸其他部分,就會變的很難。經典的例子是各類CMF,drupal, wordpress,比起框架來已經更接近應用了。

        如果一個框架能實現的功能很多,也很容易修改或定義其中的功能細節,那么這個框架往往需要寫非常多的業務代碼來填充起這些允許自定義的部分(因為如果這些部分有預設值,這個框架就落回到上一個類型)。一般而言的“重”框架往往是這種類型。

        而一個框架如果要寫的業務代碼不多,也還是能夠輕松的改變其中的功能,那么這個框架往往無法內置很多功能,需要開發者自己動手拼積木。

        以上是我總結的框架的三角原理,業務代碼(少),內置功能(多)和內部掌控(易)三者不可得兼。

        作為開發者,我選擇放棄內置功能的數量,因為我覺得這是唯一可以由外部彌補的,不屬于一個框架本身素質。

        啰嗦了這么多,這是一個以PSR為核心的,自帶DI機制的微框架,其他一切皆可選配。如果你喜歡Slim,但又嫌棄他自身不模塊化沒法換輪子,DI不正宗搞service locator反模式,不妨了解一下。如果你還不了解Slim,還不知道為啥那么多老司機上手就是Slim,但又懶得四處安利Slim這么小的框架究竟好在哪里,那也可以和Slim一起看下。

        http://litphp.github.io/blog/... (全英文預警)

        查看原文

        贊 10 收藏 4 評論 3

        mcfog 評論了文章 · 2018-10-01

        開源 PHP 項目找隊友、顧問、指導、貢獻者等等

        介紹站點還沒做,先直接甩代碼鏈接了

        https://github.com/litphp/litphp

        Lit是什么?

        Lit是我一直在擼的個人框架,按第一次上傳代碼來說歷史 超過4年 了,從還能支持PHP5.2的第一版開始一直(龜速)迭代,同時為了跟上時代的發展又反復重寫,到今天已經形成了一個以依賴注入Air,中間件管理Nimo為核心的PSR-7 + PSR-15組件群

        為什么現在?

        簡單來說,PSR-15正式落地,我認為這是一個新的PHP框架出現的最好時機,偉大的Laravel和Symfony框架背負著http-foundation的包袱,Zend框架雖然推出了Expressive但并沒有全力去推。

        現在的狀況?

        第一個針對psr/http-server-middleware接口的版本 v0.8.0已經release,這個版本同時進行了最低程度的測試覆蓋,雖然仍然是一個0文檔沒有社區的框架,但已經完全可用了(不如說其實lit的每個版本都是我一邊寫業余小玩意兒的同時一邊迭代的)

        關于v0.9,這個1.0之前最后的版本號(希望……我希望盡可能別0.10)的目標和進度可以 參考這里。三句話說完的話,完善文檔和測試、優化API接口使之能無縫升級到第一個長期支持的v1.0,以及可能的話建立基礎的社區。

        實際項目例子?

        https://github.com/team-a7s/d... (PHP代碼在kadath目錄)目標版本暫時是v0.8

        你能幫上我的?

        • 試用。雖然目前 文檔 非常少,但畢竟定位輕量級框架,只要關注PSR-15的同學,看 QuickStart 應該還是能很快上手的。 最麻煩的DI部分我會盡快補充文檔……
        • 幫助完善文檔
        • 幫助完善測試
        • 幫助建立周邊站點和設施(主站、CI、Contributor Guideline等等),以及相應的美術支持
        • 重構/改進的建議或PR
        • 或者能幫我勾搭上能夠合作的隊友

        我可以提供的?

        必須的contributor credits、litphp組織成員、author列表等等開源社區應當提供的一切

        一些(好吧,不多)其他種種原因未公開的以前的個人項目的源碼訪問

        聯系我 => mcfogw在gmail


        更新了主頁 http://litphp.github.io

        查看原文

        mcfog 評論了文章 · 2018-10-01

        開源 PHP 項目找隊友、顧問、指導、貢獻者等等

        介紹站點還沒做,先直接甩代碼鏈接了

        https://github.com/litphp/litphp

        Lit是什么?

        Lit是我一直在擼的個人框架,按第一次上傳代碼來說歷史 超過4年 了,從還能支持PHP5.2的第一版開始一直(龜速)迭代,同時為了跟上時代的發展又反復重寫,到今天已經形成了一個以依賴注入Air,中間件管理Nimo為核心的PSR-7 + PSR-15組件群

        為什么現在?

        簡單來說,PSR-15正式落地,我認為這是一個新的PHP框架出現的最好時機,偉大的Laravel和Symfony框架背負著http-foundation的包袱,Zend框架雖然推出了Expressive但并沒有全力去推。

        現在的狀況?

        第一個針對psr/http-server-middleware接口的版本 v0.8.0已經release,這個版本同時進行了最低程度的測試覆蓋,雖然仍然是一個0文檔沒有社區的框架,但已經完全可用了(不如說其實lit的每個版本都是我一邊寫業余小玩意兒的同時一邊迭代的)

        關于v0.9,這個1.0之前最后的版本號(希望……我希望盡可能別0.10)的目標和進度可以 參考這里。三句話說完的話,完善文檔和測試、優化API接口使之能無縫升級到第一個長期支持的v1.0,以及可能的話建立基礎的社區。

        實際項目例子?

        https://github.com/team-a7s/d... (PHP代碼在kadath目錄)目標版本暫時是v0.8

        你能幫上我的?

        • 試用。雖然目前 文檔 非常少,但畢竟定位輕量級框架,只要關注PSR-15的同學,看 QuickStart 應該還是能很快上手的。 最麻煩的DI部分我會盡快補充文檔……
        • 幫助完善文檔
        • 幫助完善測試
        • 幫助建立周邊站點和設施(主站、CI、Contributor Guideline等等),以及相應的美術支持
        • 重構/改進的建議或PR
        • 或者能幫我勾搭上能夠合作的隊友

        我可以提供的?

        必須的contributor credits、litphp組織成員、author列表等等開源社區應當提供的一切

        一些(好吧,不多)其他種種原因未公開的以前的個人項目的源碼訪問

        聯系我 => mcfogw在gmail


        更新了主頁 http://litphp.github.io

        查看原文

        mcfog 發布了文章 · 2018-09-30

        開源 PHP 項目找隊友、顧問、指導、貢獻者等等

        介紹站點還沒做,先直接甩代碼鏈接了

        https://github.com/litphp/litphp

        Lit是什么?

        Lit是我一直在擼的個人框架,按第一次上傳代碼來說歷史 超過4年 了,從還能支持PHP5.2的第一版開始一直(龜速)迭代,同時為了跟上時代的發展又反復重寫,到今天已經形成了一個以依賴注入Air,中間件管理Nimo為核心的PSR-7 + PSR-15組件群

        為什么現在?

        簡單來說,PSR-15正式落地,我認為這是一個新的PHP框架出現的最好時機,偉大的Laravel和Symfony框架背負著http-foundation的包袱,Zend框架雖然推出了Expressive但并沒有全力去推。

        現在的狀況?

        第一個針對psr/http-server-middleware接口的版本 v0.8.0已經release,這個版本同時進行了最低程度的測試覆蓋,雖然仍然是一個0文檔沒有社區的框架,但已經完全可用了(不如說其實lit的每個版本都是我一邊寫業余小玩意兒的同時一邊迭代的)

        關于v0.9,這個1.0之前最后的版本號(希望……我希望盡可能別0.10)的目標和進度可以 參考這里。三句話說完的話,完善文檔和測試、優化API接口使之能無縫升級到第一個長期支持的v1.0,以及可能的話建立基礎的社區。

        實際項目例子?

        https://github.com/team-a7s/d... (PHP代碼在kadath目錄)目標版本暫時是v0.8

        你能幫上我的?

        • 試用。雖然目前 文檔 非常少,但畢竟定位輕量級框架,只要關注PSR-15的同學,看 QuickStart 應該還是能很快上手的。 最麻煩的DI部分我會盡快補充文檔……
        • 幫助完善文檔
        • 幫助完善測試
        • 幫助建立周邊站點和設施(主站、CI、Contributor Guideline等等),以及相應的美術支持
        • 重構/改進的建議或PR
        • 或者能幫我勾搭上能夠合作的隊友

        我可以提供的?

        必須的contributor credits、litphp組織成員、author列表等等開源社區應當提供的一切

        一些(好吧,不多)其他種種原因未公開的以前的個人項目的源碼訪問

        聯系我 => mcfogw在gmail


        更新了主頁 http://litphp.github.io

        查看原文

        贊 15 收藏 4 評論 6

        mcfog 贊了文章 · 2018-08-17

        程序員職場算法,一條真正的發展捷徑

        學員面試失敗了,來找我咨詢。
        “老師,我覺得整個過程,沒什么問題啊?!?br>我問他,除了技術,你和HR還聊了什么呀?
        他說,HR問我為什么選擇他們公司。
        我就實話實說唄,為了公司能提供給我一個成長的平臺;
        積累項目經驗,學習最新的技術……
        我說,問題就在于:
        你剛剛所說,可曾有那么一點點,跟人家公司有關系的?
        圖片描述
        以我這些年的經驗,這不是個例。
        身在職場,就要按照職場的規則;
        ?
        職場的規則

        所謂“職場規則”,說白了就是四個字:公平交易。
        俗話說,一手交錢,一手交貨。其他內容,概不關心。
        ?
        試想,你去停車,工作人員說:
        我在這停車場都干了十年了,你多交點兒停車費唄?
        或者,你去買西瓜,瓜農說:
        最近家里要裝修,缺錢,西瓜300塊一斤,好不好?
        作何感想?為什么覺得不可理喻?
        這交易,不公平。
        圖片描述?

        企業需要的,是我們能提供的價值;
        只要按時完成任務,提供足夠多的價值;
        你加不加班,每晚熬到幾點,上班穿大褲衩還是西裝革履:
        這些跟交易本身沒有太大關系,所以通通不重要。
        ?
        至于你能不能獲得成長,在工作中的心路歷程;
        以及敲代碼時的喜怒哀樂……
        更是和公司沒有關系。
        職場呀,成年人啊,公平交易啊。
        ?
        所謂的發展機會、環境福利、薪資獎金;
        這是企業提供給個人的。
        交易要公平,就需要我們拿“貨”來換。
        對于勞動力的買家,企業只認價值。
        越早認識到這一點,努力的價值就越大。
        ?

        從心態上順應規則

        想要利用規則,就要先順應它。
        很多學員身體已經走出校門,心智還是個大學生。
        好學生,未必是好員工,角色轉變,至關重要。
        ?
        學生時代,好學,被看成是一種美德。
        可到了職場,好學就變成了個人的事情;
        要是因為好學而耽誤了工作,后果會很嚴重。
        ?
        圖片描述
        有學員曾經很不理解:學了技術,工作效率高了,不是公司受益嗎?
        可是當你能力提升后,薪資同樣會提升。
        站在企業的角度,成本也提高了。
        學到的技術,是你的本事,也是你的“私事”;
        公司或者平臺的作用,只是把你的本事兌換成財富,僅此而已。
        ?
        好學,自然沒錯,況且在IT這個行業。
        但方式方法,一定不要越過“公平交易”這個底線。
        在國外,這叫“契約精神”。
        企業花錢想滿足的需求,是出活;而不是讓干活的人成長。
        在出活的過程中成長,沒問題,但過度關注成長,容易主次混淆。
        ?
        上面的話,有些同學可能認為我是站在公司或者老板的角度;
        可認真想想,其實企業的需求,同樣是市場需求。
        我們個人想在市場經濟發達的社會,分上一杯羹。
        不關心身邊的實際項目需求、市場需求,而是按照自己的想象和推測。
        鉆研“以后可能用得上的炫酷技術”,舍本逐末了。
        圖片描述

        具體怎么做,才能適應職場規則?

        一句話:做好當下的事,在實戰中積累核心競爭力。
        到了35歲,還在擔心被時代拋棄的程序員;
        一般是這山望著那山高,總在挑一條“最好的路”。
        關注了“人工智能”,了解過“三大框架”。
        而現實中,還在做著“切圖”之類的基礎工作。
        時間就在不斷地關注和焦慮中浪費掉:
        ?
        很多學員總想著:等我學了足夠多的知識;
        成長起來之后,就能解決實際工作中的問題。
        那么學什么好呢?從此陷入選擇困難癥……
        還不如在工作中遇到了問題,去解決它,這才能獲得真正的成長。
        圖片描述
        ?
        很少有人,會想著把最新的技術,用來解決當前問題;
        比如:我怎么用Vue,把現在的產品優化一下呢?
        ?
        職場的財富邏輯,是你能解決多少實際問題,就能收獲多大價值。
        不去解決手邊現成的問題,卻囤了一堆課程,學了一堆知識點,還沒有實踐機會。
        這不就是屠龍之術么:
        練了半天,龍沒來,屠龍刀倒是生銹了;
        最后只能當廢鐵賣掉,還耽誤半天功夫。

        大部分高端技術,是被問題激發出來的。
        換句話說,任何人,都是在解決業務邏輯中成長起來的。
        淘寶網的框架,是一個阿里的大牛寫的。
        人家可不是學了很多東西,然后一氣呵成。
        而是在搭完框架之后,不斷發現問題,又不斷完善;
        才有了這樣一個優秀作品,才收獲成長。
        圖片描述?

        之前面試過一個程序員,講起來自己研究過的“高端技術”,滔滔不絕。
        我問道:你所研究的知識,對你當時的工作,有什么促進作用嗎?
        或者說,解決了什么實際項目中的問題呢?優化了什么進程?
        他沉默了一小會兒,巧妙地轉移了話題。
        ?
        根據我的經驗,HR可能不關心你研究了多少高端技術;
        更不關心你敲代碼的喜怒哀樂,而是上來就問:
        能干什么活?操作過什么項目?
        或者是:來了,能立馬干活嗎?
        圖片描述?

        大家也看到了,實戰給了我們成長的方向;
        同樣保證了我們努力的價值。
        ?
        回到之前的邏輯,當你能夠解決實際項目中的任何問題;
        在實戰中積累了大量的經驗,能夠獨當一面的時候。
        按照“公平交易”的原則;
        薪資是不可能原地踏步的。
        職場規則,針對的可不是個人,而是整個人才市場。
        這才是符合職場的算法,如果說程序員的職業發展;
        真的有捷徑的話,我相信,這條路就是,并且是最簡單的一條。
        ·END·

        查看原文

        贊 12 收藏 3 評論 4

        mcfog 贊了文章 · 2018-01-25

        小而美的backbone

        本文已同步在我的博客

        在這個reactvue如日中天、jquery逐漸被大家拋棄的年代,我還是想要來說一說backbone。

        16年6月初,在沒有任何前端框架使用經驗、js水平也較一般的情況下,被告知需要在幾個工作日內搭建完成一個后臺管理系統,沒有頁面設計稿、沒有組件庫,一切都是從零開始。當時面臨兩個選擇,backbone和react。雖然我很希望能夠拿react來練手,但是考慮到學習成本和項目時間問題,leader還是建議我使用backbone來完成,就這樣,一直用到差不多現在。雖然到項目后期業務場景越來越復雜,backbone的這套技術棧體現出越來越多的問題,但是對于小型項目來說,我還是認為backbone是個不錯的選擇,而且學習成本低,上手極快~

        backbone是個非常輕量的mvc庫,本文將基于backbone的源碼談一談其實現的核心部分,以及其中一些巧妙的思想和代碼實現技巧。

        事件機制(Events)

        事件部分的核心邏輯其實比較簡單,簡化一下可以用如下的偽代碼來表示:

        var events = {
            evt1: handlers1,
            evt2: handlers2,
            ...
        }
        
        //注冊事件
        function on(name, callback) {
            const handlers = events[name] || (events[name] = []);
            handles.push(callback);
        }
        
        //觸發事件
        function trigger(name) {
            if (!events[name]) {
                return;
            }
            const handlers = events[name];
            for (let i = 0, len = handlers.length; i < len; i++) {
                handlers[i]();
            }
        }
        
        //解除綁定
        function off(name) {
            delete events[name];
        }
        

        當然了,以上寫法有很多細節的地方沒有加入進來,比如上下文綁定、對多種傳參方式的支持、觸發事件時對事件處理器傳參的處理等等。

        我們知道,對于MVC來說,M(模型)的變化會反映在V(視圖)上,實際上是視圖監聽了模型的變化,再根據模型去更新自身的狀態,這當中最重要的一個功能就是監聽(listen)。該功能也是由Events部分實現的,包括:listenTo、stopListening

        listenToon類似,都是監聽一個事件,只不過listenTo是監聽其他對象的對應事件,而on是監聽自身的對應事件。stopListening同理。比如:

        a.on('testevent', function(){
            alert('1');
        });
        a.trigger('testevent');

        如果其他對象希望監聽atestevent事件呢?則可以通過listenTo來實現:

        b.listenTo(a, 'testevent', function() {
            alert('catch a\'s testevent');
        })

        其中第一個參數為要監聽的對象,第二個參數為事件名稱

        當調用on方法的時候,會為對象自身創建一個_event屬性;而調用listenTo方法時,會為監聽對象創建_event屬性,同時為了記錄監聽者,被監聽對象還會創建一個_listeners屬性:

        a.on('testevent', handlers1);

        a會變成:

        {
            _events: {
                testevent: [handlers1]
            },
            on: function() {
                //...
            }
            ...
        }

        當有其他對象監聽a時,如:

            b.listenTo(a, 'testevent', handlers2);

        a會變成:

        {
            _events: {
                testevent: [handlers1, handlers2]
            },
            _listeners: b,
            on: function() {
                //...
            }
            ...
        }

        在事件機制的實現部分,除了核心邏輯之外,在對一些方法的使用上,也很考究。為了綁定函數執行的上下文,我們經常會使用apply,call這些方法,而源碼中多次提到apply的執行效率要低一些,因此,有這樣的實現:

        // A difficult-to-believe, but optimized internal dispatch function for
        // triggering events. Tries to keep the usual cases speedy (most internal
        // Backbone events have 3 arguments).
        var triggerEvents = function(events, args) {
            var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
            switch (args.length) {
              case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
              case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
              case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
              case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
              default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); return;
            }
        };

        有關為什么callapply的效率更高的解釋可以參考這篇文章

        模型(Model)

        model用于維護數據,其中最關鍵的是對數據的更新部分,即set

        // Trigger all relevant attribute changes.
        if (!silent) {
            if (changes.length) this._pending = options;
            for (var i = 0; i < changes.length; i++) {
                this.trigger('change:' + changes[i], this, current[changes[i]], options);
            }
        }
        
        // You might be wondering why there's a `while` loop here. Changes can
        // be recursively nested within `"change"` events.
        if (changing) return this;
        if (!silent) {
            while (this._pending) {
                options = this._pending;
                this._pending = false;
                this.trigger('change', this, options);
            }
        }
        this._pending = false;
        this._changing = false;
        return this;

        每次set數據的時候,根據數據變化的部分,使用trigger方法觸發相應的事件;在set數據時,如果不希望觸發change事件,可以設置silenttrue。

        這部分比較容易讓人產生疑惑的是while循環部分,這個while循環有什么用呢?舉個例子:

        new Model.on("change", function() {
            console.log('model change');
        }).set({
            a: 1
        });

        以上代碼是最簡單的情況,監聽change事件,當model變化時,打印出model change
        在源碼中,當第一次進入while后,緊接著this._pending被置為false,而事件觸發回調函數也不會更改this._pending的值,因此再次判斷時條件不成立,while內的代碼段只會執行一次。

        但是實際情況往往不是這么簡單,如代碼注釋中所說,有可能會有嵌套的情況,比如:

        new Model.on("change", function() {
            this.set({
                b: 1
            })
        }).set({
            a: 1
        });

        在這種情況下,第一次trigger觸發change的回調函數中,又再次對model進行了更新操作,

        this.set({
            b: 1
        })

        每次set時,會更新this._pendingtrue,這樣當set b后,就會再次進入while內,觸發change事件。而如果沒有使用while循環的話,對b屬性更新的操作就無法觸發change事件,導致其監聽者到無法根據最新的數據更新自身狀態。

        視圖(View)

        View部分的實現比較簡單,其中最主要的是events部分,通常在一個View中,都會綁定一些dom事件,比如:

        {
            'click .preview-btn': 'preview',
            'click .save-btn': 'save'
        }

        主要有兩點需要說明:

        • backbone中是采用的事件委托的方式綁定事件,因此,一些不冒泡的事件,比如scroll,是無法通過這樣的方式綁定的
        • 回調函數會保持正確的this指向。backbone內部進行了處理
        delegateEvents: function(events) {
            events || (events = _.result(this, 'events'));
            if (!events) return this;
            this.undelegateEvents();
            for (var key in events) {
                var method = events[key];
                if (!_.isFunction(method)) method = this[method];
                if (!method) continue;
                var match = key.match(delegateEventSplitter);
                this.delegate(match[1], match[2], _.bind(method, this));
            }
            return this;
        }

        結語

        以上部分介紹了backbone中最核心部分的實現機制??梢钥吹狡鋵崿F非常的簡單,但是對于小型項目來說,確實可以幫我們做一些對數據的維護和管理工作,提高開發效率。但是隨著業務逐漸復雜,會越來越發現,backbone所能做的實現有限,而對于數據維護部分也非常不方便,尤其是需要是對多個模塊間的通信和數據維護問題。后續我會結合在復雜業務中的使用談一談backbone的缺點,以及更優的框架能帶來的便利。

        說句題外話,雖然去年由于時間原因選擇了backbone,這一年基本沒有在復雜業務場景中使用react技術棧,都是自己做個小demo練手。但是也正是因為有了使用backbone去寫復雜業務的經歷,在數據維護上和模塊間通信上非常麻煩,以及backbone渲染dom時直接全部更新的會導致的頁面渲染性能問題,才更讓我感覺react + redux的美好。知其然,還需知其所以然啊~ ~
        不然我覺得我可能會一直疑惑為什么要用一套這么復雜的技術棧,異步請求這塊寫起來還那么麻煩。這么看,壞事也算是好事了吧~~

        查看原文

        贊 6 收藏 12 評論 3

        mcfog 贊了回答 · 2017-12-31

        解決CSRF 生成 token 的方式這樣可以攻擊嗎?

        在中間網站我請求兩次,第一次通過 GET 方式請求這個表單頁面從而獲取 token,第二次帶上這個 token 發起 POST 請求,這樣不就成功偽裝了嗎?我這個想法應該有問題,但好像又可以,錯在哪?

        中間網站是什么?

        如果是指中間人攻擊,那么,你應該關注的是 HTTPS。CSRF 不處理中間人攻擊。

        如果是指第三方網站,那么,除非你的網站通過 Access-Control-Allow-Origin 頭允許,否則第三方網站無法讀取請求返回的內容(跟其它一些跨域請求的處理一樣,能請求,但是未經允許不得訪問),也就拿不到 token。


        PS: 這么基礎的問題,那么多回答,竟然只有一個稍微靠譜點的…………

        關注 10 回答 7

        mcfog 關注了問題 · 2017-12-19

        解決PHP可變長參數(...)和生成器問題

        問題來源于 http://www.tvxinternet.com/q/10... 這里??戳?a href="/u/elarity">@elarity 的回答,他使用了200000的元素插入到redis集合。于是乎我使用了1百萬個元素數組來插入,在我這里是內存溢出的,所以我使用了生成器的方式

        function xrange() {
                for ($i=0; $i<1000000; $i++) {
                        yield $i;
                }
        }
        $r = xrange();
        
        $redis = new Redis();
        $redis->connect('127.0.0.1', 6379);
        
        $key = 'jimu';
        $redis->del($key);
        $begin = microtime(true);
        $redis->sadd($key, ...$r);
        
        $end = microtime(true);
        echo ($end - $begin) . "\n";

        輸出結果:

        [vagrant@localhost ~]$ php redis.php 
        1.2786898612976
        [vagrant@localhost ~]$

        然后redis-cli中確實有了一百萬個元素。那么當我把代碼中的一百萬修改為一千萬的時候又報內存溢出

        [vagrant@localhost ~]$ php redis.php 
        PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in /home/vagrant/redis.php on line 6
        
        Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 32 bytes) in /home/vagrant/redis.php on line 6

        根據我理解的生成器知識不應該出現內存溢出的情況。因為自始至終生成器xrange只占用一個變量($i)內存?
        所以我猜測是不是$redis->sadd($key, ...$r);這一步的時候...$r依然會解析成大數組。 現在不知道如何證實。


        補充:
        我在sadd之前使用var_dump(...$r);exit;發現輸出的都是

        int(999775)
        int(999776)
        int(999777)
        int(999778)
        int(999779)
        int(999780)
        int(999781)

        這樣可以證明生成器確實是一個一個產出值的。那么為什么將...$r傳入到sadd()的時候還報內存不足呢?不明白這個...的原理,還請大佬們指點。

        關注 5 回答 2

        mcfog 回答了問題 · 2017-12-14

        解決PHP可變長參數(...)和生成器問題

        好久沒看到想答的問題了,來一波

        a. 這個問題和redis毫無關系

        b. 上代碼

        <?php
        //splat.php
        function gen() {
          global $argv;
          $max = $argv[1];
          while($max--) {
            yield(str_repeat('x', 10000));
          }
        }
        
        function noop() {
        
        }
        
        function getargs() {
          $arg = func_get_args();
        }
        
        function splat(...$arg) {
        
        }
        
        function printmemory($msg) {
          printf("%s: %d/%d\n", $msg, memory_get_usage(), memory_get_peak_usage());
        }
        
        printmemory(__LINE__);
        $gen = gen();
        printmemory(__LINE__);
        foreach(gen() as $r) {
          crc32($r);
        }
        printmemory(__LINE__);
        $argv[2](...$gen);
        printmemory(__LINE__);
        ~/Desktop $ php splat.php 10000 getargs
        27: 357896/394272
        29: 358504/394272
        33: 370816/394272
        35: 382912/123779064
        ~/Desktop $ php splat.php 10000 noop
        27: 357896/394272
        29: 358504/394272
        33: 370816/394272
        35: 382912/123250912
        ~/Desktop $ php splat.php 10000 splat
        27: 357896/394272
        29: 358504/394272
        33: 370816/394272
        35: 382912/123779064
        ~/Desktop $ php splat.php 1000 splat
        27: 357896/394272
        29: 358504/394272
        33: 370816/394272
        35: 382912/12695544
        ~/Desktop $ php splat.php 100 splat
        27: 357896/394272
        29: 358504/394272
        33: 370816/394272
        35: 382912/1607672

        c. 解釋

        27-29-33之間,幾乎沒有內存占用,這是所謂的"生成器節省內存”的現象,也就是各種相關文章里都會解釋的,在30行迭代生成器的時候,每次循環都會進到生成器內部去yield一次,產生一個大字符串,下次循環的時候循環變量又重新被賦值,之前的字符串自然會被GC回收,所以無論循環多大多少次,占用的內存是穩定的(包括上面的$gen=gen()也是幾乎不占內存的)

        33-35,無論被調用的函數如何,甚至noop函數,都一樣會占用大量內存,占用內存的量明顯和次數成正比,也就是說生成器的內容被合并到一起而占用了一整塊內存。這其實很容易解釋,幾乎的所有語言“調用函數”的過程都是類似的

        1. 首先計算所有參數,形成參數列表
        2. 生成call frame(其中包含調用被調雙方、文件行號、參數列表等等信息),壓入call stack中
        3. 控制權移交給函數內部

        (當然省略了超級多的細節,比如實參形參的映射/copy啊,內存管理啊等等什么的,和本題無關)

        ...$args這個操作符其實影響的就是第一個階段,計算參數的時候,看到...操作符,就需要展開其中的參數來形成參數列表,那么用生成器的場合,這個階段內存就從原有生成器的少量占用變成了完整的占用了,所以即使是空的noop函數也會占用幾乎一樣多的內存,你的理解是正確的

        回到原題的那個redis問題的話,因為重復調用redis方法一定會占用大量的額外網絡開銷,而一次性批量插入又鐵定逃不開內存占用(其實你想redis擴展要發送這個批量的指令給redis,那么這塊內存肯定是要的),比較好的方式就是分組了,每1000個或者10000個合并成一次$redis調用,mysql也好其他場景也是類似的

        關注 5 回答 2

        認證與成就

        • 獲得 1433 次點贊
        • 獲得 39 枚徽章 獲得 0 枚金徽章, 獲得 11 枚銀徽章, 獲得 28 枚銅徽章

        擅長技能
        編輯

        開源項目 & 著作
        編輯

        (??? )
        暫時沒有

        注冊于 2014-04-03
        個人主頁被 16.6k 人瀏覽

        一本到在线是免费观看_亚洲2020天天堂在线观看_国产欧美亚洲精品第一页_最好看的2018中文字幕