<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          一些不太常見的前端開發(fā)問題,你遇到過嗎? ( TS 相關(guān)知識較多)

          共 7556字,需瀏覽 16分鐘

           ·

          2022-02-21 16:04

          點(diǎn)擊下方星標(biāo)眾號,實(shí)用前端技術(shù)文章及時(shí)了解

          前言

          終于湊齊一些有趣的bug與問題了, 比如在ts方面做了深入的研究, 國際化開發(fā)方面有了一些思考等等

          1: url的編碼操作

          當(dāng)我們通過url來傳遞一些信息的時(shí)候, 可能會出現(xiàn)一些讀取的問題,我們常用encodeURIencodeURIComponent進(jìn)行編碼后再進(jìn)行傳遞, 但是我發(fā)現(xiàn)項(xiàng)目中所有地方都用encodeURIComponent, 為什么會這樣這兩種有什么區(qū)別?

          因?yàn)?code style="font-size: 14px;border-radius: 4px;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">encodeURI并不會對;/?:@&=+$,#之類的字符進(jìn)行轉(zhuǎn)移, 這就會導(dǎo)致某些特殊情況下解析uri出現(xiàn)問題(后端使用的語言不同導(dǎo)致解析方式不同), encodeURIComponent會轉(zhuǎn)義URI各個(gè)部分的標(biāo)點(diǎn)符號比如常用的連接符&?, 也就是說它轉(zhuǎn)義的更徹底安全性更高, 所以建議盡可能使用encodeURIComponent來處理。


          2: 國際化項(xiàng)目左右翻轉(zhuǎn)(前端 RTL 適配)

          來到國際化前端團(tuán)隊(duì)才學(xué)習(xí)到, 從左往右寫的為"LTR", 從右往左寫的為"RTL", 比如'希伯來語'、'阿拉伯語'等,如果你的公司要開發(fā)一款app提供給多個(gè)國家使用, 那就要考慮到有的國家書寫文字是從右往左的, 并且很多圖片也要從右往左展示, 比如把返回按鈕放在右上方!

          我們要做的就是文字書寫的翻轉(zhuǎn)、輸入框的翻轉(zhuǎn)、圖標(biāo)的自身翻轉(zhuǎn)以及位置的鏡像、但是某些圖標(biāo)不用反轉(zhuǎn)比如 "時(shí)鐘" 亦或者 30%不用反轉(zhuǎn)為%03, 當(dāng)然這些頭疼的問題也是有成熟的解決方案的。



          第一種: dir="rtl"屬性設(shè)置

          body元素加上屬性dir="rtl", 瀏覽器就可以自動翻轉(zhuǎn)了, 沒試過的快試試很好玩的。

          缺點(diǎn)也很明顯, 就比如我們的css屬性margin: left; 仍然是作用于左邊。

          第二種: rtlcss

          rtlcss的官網(wǎng), 他的實(shí)現(xiàn)思路就是配合rtl屬性使用, 將頁面上的left相關(guān)屬性都轉(zhuǎn)為right屬性, 核心思想就是某些屬性的全局替換。

          3: 后端int64類型出錯(cuò)

          公司內(nèi)部有一個(gè)庫可以把后端的rpc接口規(guī)范直接轉(zhuǎn)成ts規(guī)范供前端使用, 但是突然有一天出現(xiàn)了類型錯(cuò)誤, 比如后端規(guī)定返回參數(shù)為code數(shù)字類型, msg為字符串類型, 那么就會生成如下文件:

          export?type?XxxxApi?=?{
          ???code:?number;
          ???msg:?string;
          }

          但是一天夜里后端返回的code對應(yīng)的類型竟然變成了string, 我和同事查看了后端同學(xué)的代碼, 定義的也的確是int類型, 但不過不是int32而是int64, 原來是因?yàn)?code style="font-size: 14px;border-radius: 4px;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">js的數(shù)字的極限是2的53次方:


          所以才采用string的方式來表達(dá)int64這個(gè)數(shù)據(jù)類型, 后端同學(xué)將類型改為int32就沒問題了, 當(dāng)然啦后端同學(xué)擅自改類型不通知我們要提出批評??。

          4: 開發(fā)時(shí)候樣式好好的, 打包后就出問題了

          * bug 場景
          ???? 明明開發(fā)時(shí)候好好的, 但為什么打包之后就會出現(xiàn)各種錯(cuò)誤, 比如樣式丟失, 這里說下原因之一:

          很久之前的某天我把開發(fā)好的前端項(xiàng)目代碼發(fā)布到了服務(wù)器上, 在我本地訪問時(shí)樣式很完美, 但是當(dāng)我通過測試環(huán)境url打開這個(gè)項(xiàng)目的時(shí)候, 竟然表格樣式有些崩壞寬高與我本地的不一樣, 但是我沒有想明白bug的原因, 就去與 '同學(xué)a' 交流為什么出現(xiàn)這種現(xiàn)象。

          '同學(xué)a' 說是因?yàn)橛脩舻臑g覽器和我不一樣導(dǎo)致的, 可是我就是用戶, 開發(fā)就在我的瀏覽器上也是我用瀏覽器訪問的測試環(huán)境, 但是是同一個(gè)瀏覽器, 但'a同學(xué)'堅(jiān)持說不可能發(fā)生這種狀況, 我就給他演示了一遍從開發(fā)到發(fā)布到測試環(huán)境的全流程, 看到bug確實(shí)再次出現(xiàn)的他說是我'人品'的問題.... (后來是通過改了一些css的寫法解決的)

          我對這個(gè)事情印象還是比較深刻的, 但在今年的某一天, 我在配置webpack的時(shí)候突然發(fā)現(xiàn)了一個(gè)問題點(diǎn), 比如postcss在配置的時(shí)候會有一個(gè)設(shè)置, 在developmentproduction兩種模式下分別兼容到主流瀏覽器什么版本, 那這里其實(shí)就很可能是問題所在, 因?yàn)獒槍﹂_發(fā)與打包進(jìn)行了不同的翻譯, 這就會導(dǎo)致無法預(yù)期的錯(cuò)誤產(chǎn)生, 雖然已經(jīng)不在那家公司了當(dāng)年的代碼已經(jīng)找不到了, 但想到這點(diǎn)還是會很強(qiáng)烈的感覺到之前毫無頭緒的問題有了一個(gè)解決方向!

          5: pc端喚起WhatsApp & Email 為何失效

          URL Schema

          要想學(xué)習(xí)喚起app就要先知道Schema是什么, 我通俗點(diǎn)講一下, 就是你下載到系統(tǒng)里的每個(gè)app其實(shí)都可以注冊一個(gè)屬于它的url地址, 這個(gè)地址你可以理解為就是Schema。

          而我們喚起某個(gè)app就可以利用這個(gè)"Schema 地址"。

          調(diào)起WhatsApp

          假設(shè)聯(lián)系人的電話號碼為 18200000000, 并且為中國的號碼區(qū)號為(86)

          -?window.open("https://wa.me/8618200000000")??會閃屏
          -?或
          -?window.open("https://api.whatsapp.com/send/?phone=8618200000000")

          不建議用window.location.href的方式跳轉(zhuǎn), 他會導(dǎo)致閃屏。

          pc端為何無法通過給定的WhatsApp號碼喚起WhatsApp?


          1. 因?yàn)閃hatsApp屬于國際軟件它要兼容區(qū)分各個(gè)國家, 所以要加上國家的區(qū)號。
          2. 當(dāng)然這個(gè)網(wǎng)址有時(shí)候不穩(wěn)定也會導(dǎo)致加載不出來。
          什么是 mailto

          mailto是一種類似http的url協(xié)議, 但它屬于本地協(xié)議(本地協(xié)議比較典型的還有file), 也就是不需要連接網(wǎng)絡(luò)就可以解析的協(xié)議, mailto的功能是喚起默認(rèn)郵箱。

          喚起Email

          指定收件人
          -?window.location.href="mailto:[email protected]"

          如果為多個(gè)人發(fā)郵件則?','?分割
          -?window.location.href="mailto:[email protected],[email protected]"

          如果要添加主題,?增加subject參數(shù)
          -?window.location.href=`mailto:[email protected]?subject=${encodeURIComponent("我是主題xxx")}`

          如果要添加主題,?增加body參數(shù)
          -?window.location.href=`mailto:[email protected]?subject=${encodeURIComponent("我是主題xxx")}&body=${encodeURIComponent('我是內(nèi)容xxx')}`

          6: React.FC

          經(jīng)常出現(xiàn)React.Fc這個(gè)函數(shù), 比如我不使用React.Fc來處理組件的函數(shù), 則在組件里面使用props.children會報(bào)錯(cuò), 我們一起進(jìn)入源碼分析一下。

          ?type?FC?=?FunctionComponent

          ;

          ????interface?FunctionComponent?{
          ????????//?第一句
          ????????(props:?PropsWithChildren

          ,?context?:?any):?ReactElement?|?null;

          ????????propTypes?:?WeakValidationMap

          ?|?undefined;
          ????????contextTypes?:?ValidationMap?|?undefined;
          ????????defaultProps?:?Partial

          ?|?undefined;
          ????????displayName?:?string?|?undefined;
          ????}

          1. FC這個(gè)type接收一個(gè)參數(shù)P, 默認(rèn)值為空對象, 而這個(gè)P。
          2. FunctionComponent就是個(gè)過度的名稱而已, 可以認(rèn)為FC就是FunctionComponent
          3. 第一句意義為第一個(gè)參數(shù)為PropsWithChildren

            類型, 第二個(gè)參數(shù)可有可無, 有則為任意類型, 返回React的dom或者返回null。

          4. 后面四個(gè)參數(shù)不是必填, 我們主要研究第一句。

          我們追查一下PropsWithChildren

          ?type?PropsWithChildren

          ?=?P?&?{?children?:?ReactNode?|?undefined?};

          只是將傳入的P的類型與{ children?: ReactNode | undefined }合并而已, 看到這里我們就明白了, 其實(shí)用React.FC包裹一下是可以幫助ts推導(dǎo)出props身上可能有children屬性。

          7: RematchRootState

          rematch官網(wǎng);

          rematch是對Redux的二次封裝, 而RematchRootStaterematch導(dǎo)出的一個(gè)ts推導(dǎo)函數(shù), RematchRootState到底做了什么令程序員脫發(fā)的操作...

          項(xiàng)目里使用了這個(gè)RematchRootState之后, 發(fā)現(xiàn)某些類型推導(dǎo)出來never類型如圖所示:


          一起探索源碼里的奧義
          export?type?RematchRootState?=?ExtractRematchStateFromModels

          export?type?ExtractRematchStateFromModels?=?{
          ????[modelKey?in?keyof?M]:?M[modelKey]?extends?ModelConfig???M[modelKey]['state']?:?never
          }?
          1. 在使用RematchRootState時(shí)我們使用typeof的形式導(dǎo)出了一個(gè)ts類型, typeof在ts里面使用就不是js里面的意義了:

            Xxx<typeof?{name:'金毛',?age:9}>

            //?此處就相當(dāng)于:

            Xxx<typeof?{name:string,?age:number}>
          2. [modelKey in keyof M]循環(huán)M對象里面所有的key值, 每次循環(huán)時(shí)命名為modelKey。

          3. M[modelKey]就是取出對應(yīng)的值, 這里特指ts里面的類型值。

          4. M[modelKey] extends ModelConfig ? M[modelKey]['state'] : never, 也就是每次取出'值', 并且此'值'符合ModelConfig類型的話則返回M[modelKey]['state']的類型, 否則返回never, 這里的extends你可以理解為is用來判斷某個(gè)值是不是符合規(guī)范的, 以后文章還會涉及extends的其他用法。

          至此我們已經(jīng)明白了, 問題一定出在M[modelKey]的類型未符合 ModelConfig的類型規(guī)范導(dǎo)致的返回的never, 那ModelConfig又是什么規(guī)范那?

          export?interface?ModelConfig?{
          ????name?:?string
          ????state:?S
          ????baseReducer?:?(state:?SS,?action:?Action)?=>?SS
          ????reducers?:?ModelReducers

          ????effects?:
          ????????|?ModelEffects
          ????????|?(?|?void?=?void>(dispatch:?RematchDispatch)?=>?ModelEffects)
          }?
          1. 由于調(diào)用ModelConfig時(shí)什么參數(shù)都沒傳, 則使用默認(rèn)值。
          2. 當(dāng)name屬性我們賦予了number類型時(shí)會導(dǎo)致錯(cuò)誤。
          3. state 對應(yīng)的S類型, 也就是默認(rèn)的any任何類型都可以。
          4. baseReducer的參數(shù)不符合規(guī)范, 或是返回值不符合規(guī)范時(shí)。
          effects 要單獨(dú)拿出來講

          第一個(gè): effects = ModelEffects

          type?ModelEffects?=?{
          ????[key:?string]:?(?this:?{?[key:?string]:?(payload?:?any,?meta?:?any)?=>?Action?},payload:?any,rootState:?S)?=>?void
          }

          export?type?Action?=?{
          ????type:?string,
          ????payload?:?P,
          ????meta?:?M,
          }?
          1. [key: string]這種寫法意思就是取出里面所有的項(xiàng)進(jìn)行循環(huán)。
          2. ModelEffects每一項(xiàng)都為函數(shù), 并且沒有返回值。
          3. ModelEffects對象的每個(gè)函數(shù)的第一個(gè)參數(shù)為一個(gè)對象, 這個(gè)對象里面值都為函數(shù), 并且返回值為Action。
          4. ModelEffects對象的每個(gè)函數(shù)的第二個(gè)參數(shù)為任意類型。
          5. ModelEffects對象的每個(gè)函數(shù)的第三個(gè)參數(shù)為rootState: S S類型, S則是我們上一步傳入進(jìn)來的, 也就是any。

          第二個(gè):

          effects?=?(?|?void?=?void>(dispatch:?RematchDispatch)?
          =>
          ?ModelEffects)
          1. M是新定義的一個(gè)泛型, 它符合Models的規(guī)范, 如果不符合的話就為void類型。
          2. 這個(gè)K就是上面默認(rèn)的string (寫到這里我都感覺好麻煩??)。

          這里是Models的類型:

          export?type?Models?=?{
          ????[key?in?K]:?ModelConfig
          }?

          每項(xiàng)都是ModelConfig, 而ModelConfig我們上面已經(jīng)講過啦。

          1. 這個(gè)函數(shù)接收的第一個(gè)參數(shù)dispatch要符合類型RematchDispatch, 這里就不再擴(kuò)展了, 往下還有特別深:
          export?type?RematchDispatchvoid>?=

          ??ExtractRematchDispatchersFromModels?&

          ????(RematchDispatcher?|?RematchDispatcherAsync)?&

          ????(Redux.Dispatch)?

          可以看出來, 這個(gè)參數(shù)的類型我們用Redux.Dispatch來定義就沒問題的。

          1. 返回值必須為: ModelEffects這個(gè)我們剛才也講過了。

          正確的用法可以是如下的樣子:

          ?effects:?(dispatch:?Redux.Dispatch)?=>?({
          ????async?FnXxx(_:?any,?state:?RootState)?{
          ??????console.log(state.xxx.xxxList)
          ????},
          ??}),?

          總結(jié)一句話就是"讀這代碼好心累"!

          8: ts 修改函數(shù)參數(shù)

          實(shí)現(xiàn): 增加函數(shù)一個(gè)參數(shù)

          假設(shè)當(dāng)前我有這樣一個(gè)type:

          ?type?Obj?=?{
          ????getX:?(a:?string,?c:?boolean)?=>?void;
          ????getN:?(a:?number)?=>?void;
          ??};

          而我希望將這個(gè)type處理成下面這個(gè)樣子:

          ?type?Obj?=?{
          ????getX:?(s:?string[],?a:?string,?c:?boolean)?=>?void;
          ????getN:?(s:?string[],?a:?number)?=>?void;
          ??};

          這里的關(guān)鍵點(diǎn)就是取到函數(shù)返回值的類型, 以及函數(shù)參數(shù)的類型集合, 實(shí)現(xiàn)代碼如下:

          ?type?Obj2?=?{
          ????[Key?in?keyof?T]:?T[Key]?extends?(...arg:?any)?=>?any
          ???????(s:?string[],?...arg:?Parameters)?=>?ReturnType
          ??????:?T[Key];
          ??};
          1. 循環(huán)泛型T里面所有的值。
          2. 如果T[Key]不滿足(...arg: any) => any則不處理, 因?yàn)?code style="font-size: 14px;border-radius: 4px;font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">T[Key]可能不是函數(shù)類型。
          3. 反之T[Key]為函數(shù)類型, 則第一個(gè)參數(shù)為s: string[]。
          4. ...arg為后續(xù)參數(shù)類型, Parameters<>為自帶方法, 可以推導(dǎo)出函數(shù)的所有參數(shù)組成的數(shù)組的類型。
          5. ReturnType<>為自帶方法, 可以推導(dǎo)出函數(shù)的返回值的類型。

          使用方法就是:

          type?NewObj?=?Obj2?
          實(shí)現(xiàn): 去掉函數(shù)第一個(gè)參數(shù)

          假設(shè)當(dāng)前我有這樣一個(gè)type:

          ?type?Obj?=?{
          ????getX:?(a:?string,?c:?boolean)?=>?void;
          ????getN:?(a:?number)?=>?void;
          ??};

          而我希望將這個(gè)type處理成下面這個(gè)樣子:

          ?type?Obj?=?{
          ????getX:?(c:?boolean)?=>?void;
          ????getN:?()?=>?void;
          ??};

          這里的關(guān)鍵點(diǎn)就是, 在ts里如何剔除數(shù)組的第一個(gè)元素, 并使用剩下的元素組成數(shù)組返回出來:

          ?type?Obj2?=?{
          ????[Key?in?keyof?T]:?T[Key]?extends?(s:?any,?...arg:?infer?Arg)?=>?any
          ????????(...arg:?Arg)?=>?ReturnType
          ??????:?T[Key];
          ??};?
          1. 這里整體的邏輯是不變的, 與上面一個(gè)原理。
          2. (s: any, ...arg: infer Arg) => any, 這里是核心, 將函數(shù)處理第一個(gè)參數(shù)以外的參數(shù)單獨(dú)拿出來命名為Arg, 然后使用Arg來定義函數(shù)的參數(shù)。
          3. infer是ts內(nèi)置的關(guān)鍵字, 有點(diǎn)類似js中的var, 他可以定義一個(gè)變量。

          使用方法就是:

          type?NewObj?=?Obj2?

          9: gzip壓縮可以用什么替代

          之前我一直認(rèn)為gzip壓縮是當(dāng)前最好的前端壓縮方案, 但是其壓縮方案并不唯一并且有著很多分類, 壓縮方式被"無狀態(tài)壓縮", "有狀態(tài)壓縮"。

          無狀態(tài)意味著它看到的任何大塊數(shù)據(jù),它都會壓縮,而不依賴于以前的輸入。速度更快但通常壓縮程度更低;有狀態(tài)壓縮查看以前的數(shù)據(jù)來決定如何壓縮當(dāng)前數(shù)據(jù),但速度較慢但壓縮好得多。

          比如zstd壓縮屬于有狀態(tài)壓縮, 會根據(jù)壓縮過程中遇到的重復(fù)代碼塊生成字典, 再遇到相同的代碼用字典里對應(yīng)的key來標(biāo)識即可。

          end

          這次就是這樣, 希望與你一起進(jìn)步。

          作者:lulu_up

          https://segmentfault.com/a/1190000040632852

          祝 您:2022 年暴富!萬事如意!

          點(diǎn)贊和在看就是最大的支持,比心??

          瀏覽 66
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                    <th id="afajh"><progress id="afajh"></progress></th>
                    免费无码又爽又刺激A片视频男男 | 九色激情网 | 大香蕉视频更新资源 | 影音先锋91视频 | 日本高清久久 |