成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

你不知道的前端SDK開(kāi)發(fā)技巧

jokester / 1148人閱讀

摘要:一個(gè)帶提示的最后對(duì)于開(kāi)發(fā)同學(xué)來(lái)說(shuō),就算不使用,也強(qiáng)烈建議使用提供注解,它會(huì)通過(guò)一些類型推導(dǎo)來(lái)檢查你的代碼的正確性,可以減少很多開(kāi)發(fā)過(guò)程中的。相對(duì)于對(duì)象,它保證了輸入的類型你定義的對(duì)象可能某一天不再只有類型的,不再需要額外的類型判斷。

作者:陳達(dá)孚

香港中文大學(xué)研究生,《移動(dòng)Web前端高效開(kāi)發(fā)實(shí)戰(zhàn)》作者之一,《前端開(kāi)發(fā)者指南2017》譯者之一,在中國(guó)前端開(kāi)發(fā)者大會(huì),中生代技術(shù)大會(huì)等技術(shù)會(huì)議發(fā)表過(guò)主題演講, 專注于新技術(shù)的調(diào)研和使用.

本文為原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明作者及出處

最近在做公司內(nèi)部的一個(gè)的一個(gè)SDK的重構(gòu),這里總結(jié)一些經(jīng)驗(yàn)分享給大家。

類型檢查和智能提示

作為一個(gè)SDK,我們的目標(biāo)是讓使用者能夠減少查看文檔的時(shí)間,所以我們需要提供一些類型的檢查和智能提示,一般我們的做法是提供JsDoc,大部分編輯器可以提供快捷生成JsDoc的方式,我們比較常用的vscode可以使用Document This。

另一種做法是使用Flow或者TypeScript,選擇TypeScript的主要原因是自動(dòng)生成的JsDoc比較原始,我們?nèi)匀恍枰谏厦孢M(jìn)行編輯,所以JsDoc維護(hù)和代碼開(kāi)發(fā)是脫離的,往往會(huì)出現(xiàn)代碼更新了,JsDoc忘記更新的情況。

除此之外開(kāi)發(fā)過(guò)程中我們無(wú)法享受到類型檢查等對(duì)SDK開(kāi)發(fā)比較重要的特性,TypeScript可以讓我們減少犯錯(cuò),減少調(diào)試的時(shí)間,另一方面這次開(kāi)發(fā)的SDK在提供出去的時(shí)候就會(huì)進(jìn)行一次相對(duì)簡(jiǎn)單的壓縮,保證引入后的體積,所以會(huì)希望壓縮掉JsDoc,而TypeScript可以通過(guò)在tsconfig.json中將declaration設(shè)置為true多帶帶的d.ts文件。

一個(gè)帶提示的SDK:

最后,對(duì)于開(kāi)發(fā)同學(xué)來(lái)說(shuō),就算不使用TypeScript,也強(qiáng)烈建議使用vscode提供//@ts-check 注解,它會(huì)通過(guò)一些類型推導(dǎo)來(lái)檢查你的代碼的正確性,可以減少很多開(kāi)發(fā)過(guò)程中的bug。

還有一個(gè)小技巧,如果你使用的庫(kù)沒(méi)有提供智能提示,你可以通過(guò)NPM/yarn-D安裝@types/{pkgname},這樣你開(kāi)發(fā)過(guò)程中就能夠享受到vscode提供的智能提示,而-D安裝到devDependencies中,也不會(huì)增加你在構(gòu)建時(shí)的代碼體積。

接口

既然提到了TypeScript,就提一下TypeScript的語(yǔ)法,基礎(chǔ)類型沒(méi)有必要贅述,而一些曾經(jīng)的高級(jí)語(yǔ)法現(xiàn)在ES6也都能支持,這里提幾點(diǎn)常用但是JavaScript開(kāi)發(fā)者不太習(xí)慣使用的語(yǔ)法。

很多人在開(kāi)始使用TypeScript的時(shí)候,會(huì)很迷戀使用any或者默認(rèn)的any,推薦在開(kāi)發(fā)中打開(kāi)tsconfig中的strict和noImplicitAny來(lái)保證盡量少的any使用,要知道,濫用any就等于你的類型檢查并沒(méi)有實(shí)質(zhì)效果。

對(duì)一些暫時(shí)不能確定內(nèi)容的對(duì)象的類型,可以使用{[key: string]: any},而不要直接使用any,后期可以慢慢擴(kuò)展這個(gè)接口直到完全消除any,同時(shí)TypeScript的類型支持繼承,在開(kāi)發(fā)過(guò)程中,可以拆解接口,利用組合繼承的方式減少重復(fù)定義。

但是接口也會(huì)帶來(lái)一個(gè)小痛點(diǎn),目前vscode的智能提醒不能很好的對(duì)應(yīng)到接口,當(dāng)你輸入到對(duì)應(yīng)變量的時(shí)候,雖然會(huì)高亮,但是高亮的也只是一個(gè)定義了名字的接口。沒(méi)有辦法直接看到接口里定義了什么。但是當(dāng)你輸入了接口里面定義的key的部分時(shí),vscode會(huì)給你完整key的提示。雖然這對(duì)開(kāi)發(fā)過(guò)程中有一點(diǎn)不夠友好,但是vscode開(kāi)發(fā)團(tuán)隊(duì)表示這是他們故意設(shè)計(jì)的,所以在API參數(shù)上可以選擇將一些必要(重要)參數(shù)用基礎(chǔ)類型直接使用,而將一些配置放入一個(gè)定義為接口的對(duì)象中。

枚舉

你有在代碼中使用過(guò):

const Platform = {
    ios: 0,
      android: 1
}

那你在TypeScript中就應(yīng)該使用枚舉:

enum Platform {
  ios,
  android
}

這樣在函數(shù)中你就可以為某個(gè)參數(shù)設(shè)置類型為number,然后傳入Platform.ios這樣,枚舉可以增加代碼的維護(hù)性,它可以利用智能提示保證你輸入的正確,不再會(huì)出現(xiàn)魔數(shù)(magic number)。相對(duì)于對(duì)象,它保證了輸入的類型(你定義的對(duì)象可能某一天不再只有number類型的value),不再需要額外的類型判斷。

裝飾器

對(duì)于裝飾器其實(shí)很多開(kāi)發(fā)者既熟悉又陌生,在redux,mobx比較流行的現(xiàn)在,在代碼中出現(xiàn)裝飾器的調(diào)用已經(jīng)很普遍,但是大多數(shù)開(kāi)發(fā)者并沒(méi)有將自己代碼邏輯抽成裝飾器的習(xí)慣。

比如在這個(gè)SDK的開(kāi)發(fā)中,我們需要提供一些facade來(lái)兼容不同的平臺(tái)(iOS, Android或者Web),而這個(gè)facade會(huì)通過(guò)插件的形式讓開(kāi)發(fā)者自己注冊(cè),SDK會(huì)維護(hù)一個(gè)注入后的對(duì)象,常規(guī)的使用方法是到了使用函數(shù)后判斷環(huán)境再判斷對(duì)象中有沒(méi)有想有的插件,有就使用插件。

實(shí)際來(lái)看,插件就是一個(gè)攔截器,我們只要阻止真正的函數(shù)運(yùn)行就可以,大概的邏輯是這樣的:

export function facade(env: number) {
  return function(
    target: object,
    name: string,
    descriptor: TypedPropertyDescriptor
  ) {
    let originalMethod = descriptor.value;
    let method;

    return {
      ...descriptor,
      value(...args: any[]): any {
        let [arg] = args;
        let { param, success, failure, polyfill } = arg;   // 這部分可以自定義
        if ((method = polyfill[env])) {
          method.use(param, success, failure);
          return;
        }
        originalMethod.apply(this, args);
      }
    };
  };
}

在SDK的開(kāi)發(fā)過(guò)程中另一個(gè)常會(huì)遇到的就是很多參數(shù)的校驗(yàn)和再封裝,我們也可以使用裝飾器去完成:

export function snakeParam(
  target: object,
  name: string,
  descriptor: TypedPropertyDescriptor
) {
  let callback = descriptor.value!;

  return {
    ...descriptor,
    value(...args: any[]): any {
      let [arg, ...other] = args;
      arg = convertObjectName(arg, ConvertNameMode.toSnake);
      callback.apply(this, [arg, ...other]);
    }
  };
}÷
泛形

泛形可以根據(jù)用戶的輸入決定輸出,最簡(jiǎn)單的例子是

function identity(arg: T): T {
    return arg;
}

當(dāng)然它沒(méi)有什么特別的意義,但是它表明了返回是根據(jù)arg的類型,在一般開(kāi)發(fā)過(guò)程中,你逃不開(kāi)范型的是Promise或者前面的TypedPropertyDescriptor這種內(nèi)建的需要類型輸入的地方,不要草率的使用any,如果你的后端返回是一個(gè)標(biāo)準(zhǔn)結(jié)構(gòu)體類似:

export interface IRes {
  status: number;
  message: string;
  data?: object;
}

那么你可以這樣使用Promise:

function example(): Promise {
    return new Promise ...
}

當(dāng)然泛形有很多高級(jí)應(yīng)用,例如泛形約束,泛型創(chuàng)建工廠函數(shù),已經(jīng)超出了本文的范圍,可以去官方文檔了解。

構(gòu)建

如果你的構(gòu)建工具是Webpack,在SDK的開(kāi)發(fā)中,盡量使用node方式調(diào)用(即webpack.run執(zhí)行),因?yàn)镾DK的構(gòu)建往往會(huì)應(yīng)對(duì)很多不同的參數(shù)變化,node方式相比純配置方式可以更加靈活的調(diào)整輸入輸出的參數(shù),也可以考慮使用rollup,rollup的構(gòu)建代碼更加面向編程方式。

需要注意的是,在Webpack3和rollup中構(gòu)建中可以使用ES6模塊化的方式構(gòu)建,這樣業(yè)務(wù)代碼引入你的SDK后,可以通過(guò)解構(gòu)引入的方式減少最終業(yè)務(wù)代碼的體積,如果你只是提供了commonjs的包,那么構(gòu)建工具的tree sharking是無(wú)法生效的,如果使用babel的話注意關(guān)閉module的編譯。

另外一種減少單個(gè)包體積的方式,可以使用lerna在一個(gè)git倉(cāng)庫(kù)里構(gòu)建多個(gè)NPM包,比起拆倉(cāng)庫(kù)可以更方便的使用公共部分的代碼,但是也需要注意對(duì)公共部分代碼的修改不要影響到別的包。

其實(shí)對(duì)于大多數(shù)的SDK的來(lái)說(shuō),Webpack3和rollup使用感受是差不多的,比較常用的插件都有幾乎同名的對(duì)應(yīng)。不過(guò)rollup有兩個(gè)優(yōu)勢(shì),一個(gè)是rollup的構(gòu)建更細(xì)化,rollup.rollup接受inputOptions生成bundle,還可以generate生成sourcemap,write生成output,在這個(gè)過(guò)程中我們可以做一些細(xì)致的工作。

第二點(diǎn)是rollup.rollup會(huì)返回一個(gè)promise,也就意味著我們可以使用async的方式來(lái)寫(xiě)構(gòu)建代碼,而webpack.run還是使用的回調(diào)函數(shù),雖然開(kāi)發(fā)者可以封裝成promise,但是個(gè)人覺(jué)得還是rollup的寫(xiě)法還是更爽一點(diǎn)。

單元測(cè)試

上周我同事做了一個(gè)在線的分享,我發(fā)現(xiàn)很多同學(xué)都對(duì)單測(cè)很感興趣也很疑惑,在前端開(kāi)發(fā)中,對(duì)涉及UI的業(yè)務(wù)代碼開(kāi)發(fā)單測(cè)試比較困難的,但是對(duì)于SDK,單元測(cè)試肯定是準(zhǔn)出的一個(gè)充要條件。當(dāng)然其實(shí)我也很不喜歡寫(xiě)單測(cè),因?yàn)閱螠y(cè)往往比較枯燥,但是不寫(xiě)單測(cè)肯定會(huì)被老司機(jī)們“教育”的~_~。

一般的單測(cè)使用mocha作為測(cè)試框架,expect作為斷言庫(kù),使用nyc提供單測(cè)報(bào)告,一個(gè)大概的單測(cè)如下:

describe("xxx api test", function() {            // 注意如果要用this調(diào)用mocha,不要用箭頭函數(shù)
  this.timeout(6000);
  it("xxx", done => {
    SDK.file
      .chooseImage({
        count: 10,
        cancel: () => {
          console.log("選擇圖片取消----");
        }
      })
      .then(res => {
        console.dir(res);
        expect(res).to.be.an("object");
        expect(res).to.have.keys("ids");
        expect(res.ids).to.be.an("array");
        expect(res.ids).to.have.length.above(0);
        uploadImg(res.ids);
        done();
      });
  });
});

同樣你可以用TypeScript寫(xiě)單測(cè),當(dāng)然在執(zhí)行過(guò)程中,不需要再編譯了,我們可以直接給mocha注冊(cè)ts-node來(lái)直接執(zhí)行,具體方式可以參考Write tests for TypeScript projects with mocha and chai?—?in TypeScript!。但是有一點(diǎn)需要提醒你,寫(xiě)單測(cè)的時(shí)候盡量依賴文檔而不是智能提示,因?yàn)槟愕拇a出錯(cuò),可能會(huì)導(dǎo)致你的智能提示也是錯(cuò)誤的,你根據(jù)錯(cuò)誤的智能提示寫(xiě)的單測(cè)肯定也是。。。

對(duì)于網(wǎng)絡(luò)請(qǐng)求的模擬可以使用nock這個(gè)庫(kù),需要在it之前增加一個(gè)beforeEach方法:

describe("proxy", () => {
  beforeEach(() => {
    nock("http://test.com")
      .post("/test1")
      .delay(200)
      .reply(200, {            // body
        test1: 1,
        test2: 2
      }, {
        "server-id": "test" // header
      });
  });
  it(...
}

最后我們用一個(gè)npm script加上nyc在mocha前面,就可以獲得我們的單測(cè)報(bào)告了。

這里我還提了幾個(gè)TypeScript使用中的小tips給大家參考。

tips: 如何在非發(fā)包情況下給內(nèi)部庫(kù)添加聲明

這個(gè)SDK在開(kāi)發(fā)過(guò)程會(huì)依賴一個(gè)內(nèi)部NPM包,為了讓這個(gè)NPM支持TypeScript調(diào)用,我們有幾種做法:

給原包添加d.ts文件,然后發(fā)布.

發(fā)布@types包,需要注意的是NPM不支持@types/@scope/{pkgname}這種寫(xiě)如果是私庫(kù)包,可以使用@types/scope_{pkgname}這種寫(xiě)法.

這次使用的標(biāo)注一個(gè)文件夾存放對(duì)應(yīng)的d.ts文件,這種方式適合開(kāi)發(fā)中進(jìn)行,如果你覺(jué)得你寫(xiě)的d.ts還不夠完美,或者這個(gè)d.ts文件目前只有這個(gè)SDK有需要,可以這么使用,在tsconfig.json中修改:

"baseUrl": "./",
"paths": {
    "*": ["/type/*"]
}

tips: 如何處理resolve和reject不同類型的promise回調(diào)

默認(rèn)的reject返回的參數(shù)類型是any,不一定能滿足我們的需要,這里給一個(gè)解決方案,并非最佳,作為拋磚引玉:

interface IPromise {
  then(
    onfulfilled?:
      | ((value: T) => TResult1 | PromiseLike)
      | undefined
      | null,
    onrejected?:
      | ((reason: U) => TResult2 | PromiseLike)
      | undefined
      | null
  ): IPromise;
  catch(
    onrejected?:
      | ((reason: U) => TResult | PromiseLike)
      | undefined
      | null
  ): Promise;

iKcamp原創(chuàng)新書(shū)《移動(dòng)Web前端高效開(kāi)發(fā)實(shí)戰(zhàn)》已在亞馬遜、京東、當(dāng)當(dāng)開(kāi)售。

iKcamp官網(wǎng):https://www.ikcamp.com

包含:文章、視頻、源代碼

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90231.html

相關(guān)文章

  • 你不知道Chrome DevTools(2):那些debug技巧

    摘要:我打算把一些上使用的高級(jí)技巧寫(xiě)成你不知道的這一系列的博文,希望大家一起學(xué)習(xí)學(xué)習(xí)。然而,這還不是最嚴(yán)重的,因?yàn)榈恼Z(yǔ)法比較寬松和隨意,所以同一功能多種寫(xiě)法,各種奇葩都有。總結(jié)前端在調(diào)試代碼的時(shí)候,知道開(kāi)發(fā)工具上的小技巧,可以提高查找問(wèn)題的效率。 Web前端開(kāi)發(fā)過(guò)程中必然會(huì)用到Chrome瀏覽器自帶的開(kāi)發(fā)者工具Chrome DevTools,使用它作為Web前端開(kāi)發(fā)性能調(diào)試的必備工具。就連隔...

    warnerwu 評(píng)論0 收藏0
  • Gradle更小、更快構(gòu)建APP奇淫技巧

    摘要:本文已獲得原作者授權(quán)同意,翻譯以及轉(zhuǎn)載原文鏈接作者譯文鏈接更小更快構(gòu)建的奇淫技巧翻譯人上個(gè)月,我有機(jī)會(huì)在發(fā)表演講。禁用更新構(gòu)建下一個(gè)技能是在中禁用更新構(gòu)建。它將使每小時(shí)檢查庫(kù)的新版本,并增加構(gòu)建時(shí)間。 本文已獲得原作者授權(quán)同意,翻譯以及轉(zhuǎn)載原文鏈接:Build your Android app Faster and Smaller than ever作者:Jirawatee譯文鏈接:...

    mcterry 評(píng)論0 收藏0
  • Gradle更小、更快構(gòu)建APP奇淫技巧

    摘要:本文已獲得原作者授權(quán)同意,翻譯以及轉(zhuǎn)載原文鏈接作者譯文鏈接更小更快構(gòu)建的奇淫技巧翻譯人上個(gè)月,我有機(jī)會(huì)在發(fā)表演講。禁用更新構(gòu)建下一個(gè)技能是在中禁用更新構(gòu)建。它將使每小時(shí)檢查庫(kù)的新版本,并增加構(gòu)建時(shí)間。 本文已獲得原作者授權(quán)同意,翻譯以及轉(zhuǎn)載原文鏈接:Build your Android app Faster and Smaller than ever作者:Jirawatee譯文鏈接:...

    zzir 評(píng)論0 收藏0
  • css相關(guān) - 收藏集 - 掘金

    摘要:在正式前端一些小細(xì)節(jié)前端掘金英文原文,翻譯未來(lái)的太讓人興奮了一方面,是全新的頁(yè)面布局方式另一方面,是酷炫的濾鏡顏色等視覺(jué)效果。老司機(jī)教你更好的進(jìn)行編程個(gè)技巧前端掘金并不總是容易處理。 CSS3 實(shí)現(xiàn)文字流光漸變動(dòng)畫(huà) - 前端 - 掘金來(lái)自百度前端技術(shù)學(xué)院的實(shí)踐任務(wù):有趣的鼠標(biāo)懸浮模糊效果,參考:http://ife.baidu.com/course/d...,用CSS3實(shí)現(xiàn)了一下,順便...

    molyzzx 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

jokester

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<