共用方式為


JavaScript 功能管理

feature-management-npm-package

JavaScript 功能管理連結庫可讓您根據功能旗標來開發和公開應用程式功能。 一旦開發新功能之後,許多應用程式都有特殊需求,例如何時應該啟用此功能,以及要在哪些情況下啟用此功能。 此連結庫提供一種方式來定義這些關聯性,並整合至常見的 JavaScript 程式代碼模式,讓公開這些功能成為可能。

功能旗標提供 JavaScript 應用程式動態開啟或關閉功能的方式。 開發人員可以在簡單的使用案例 (例如,條件陳述式) 中使用功能旗標。

以下是使用 JavaScript 功能管理連結庫的一些優點:

  • 功能管理的常見慣例
  • 低進入障礙
    • 同時支援 JSON 物件和以地圖為基礎的功能旗標來源
    • 支援在Node.js和瀏覽器環境中使用
  • 使用 Azure 應用程式組態 功能旗標存留期管理
    • 組態值可以實時變更
  • 涵蓋的簡單至複雜案例
    • 透過宣告式組態檔切換開啟/關閉功能
    • 根據對伺服器的呼叫動態評估功能的狀態

JavaScript 功能管理連結庫 開放原始碼。 如需詳細資訊,請造訪 GitHub 存放庫

注意

建議搭配 Azure 應用程式組態 使用功能管理連結庫。 Azure 應用程式組態 提供集中管理應用程式設定和功能旗標的解決方案。 如需詳細資訊,請參閱本節

功能旗幟

功能旗標是由兩個部分所組成,一個名稱和一份用來開啟功能的功能篩選清單。

功能篩選

功能篩選會定義何時應啟用功能的案例。 評估功能是否開啟或關閉時,會周遊其功能篩選清單,直到其中一個篩選條件決定應啟用功能為止。 此時,功能會被視為已啟用且周遊功能篩選會停止。 如果沒有功能篩選指出應該啟用功能,則會將其視為已停用。

例如,可以設計 Microsoft Edge 瀏覽器功能篩選。 只要 HTTP 要求來自 Microsoft Edge,此功能篩選就會啟用其所附加的任何功能。

功能旗標組態

在 JavaScript 中,開發人員通常會使用對象或對應做為主要數據結構來表示組態。 JavaScript 功能管理連結庫支援這兩種設定方法,讓開發人員有彈性地選擇最符合其需求的選項。 FeatureManager可以使用內ConfigurationObjectFeatureFlagProvider建 和 ConfigurationMapFeatureFlagProvider,從不同類型的組態讀取功能旗標。

const config = new Map([
    ["feature_management", {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": true
            },
            {
                "id": "FeatureU",
                "enabled": false
            }
        ]
    }],
    ["some other configuration", " some value"]
]);

import { ConfigurationMapFeatureFlagProvider, FeatureManager } from "@microsoft/feature-management";
const featureProvider = new ConfigurationMapFeatureFlagProvider(config);
const featureManager = new FeatureManager(featureProvider);

使用來自 Azure 應用程式組態 的功能旗標

建議您不要將功能旗標程式碼寫入應用程式,而是將其保留在應用程式外部並個別管理。 這樣做可讓您隨時修改旗標狀態,並讓那些變更在應用程式中立即生效。 Azure 應用程式設定服務提供用於管理所有功能旗標的專用入口網站 UI。 請參閱教學課程

Azure 應用程式組態 服務也會透過其 JavaScript 用戶端連結庫@azure/app-configuration-provider,直接將功能旗標傳遞至您的應用程式。 下列範例示範如何使用連結庫。

應用程式組態 JavaScript 提供者會在 物件中Map提供功能旗標。 內建 ConfigurationMapFeatureFlagProvider 有助於在此案例中載入功能旗標。

import { DefaultAzureCredential } from "@azure/identity";
import { load } from "@azure/app-configuration-provider";
import { ConfigurationMapFeatureFlagProvider, FeatureManager } from "@microsoft/feature-management";
const appConfig = await load("YOUR_APP-CONFIG-ENDPOINT",
                             new DefaultAzureCredential(), // For more information: https://learn.microsoft.com/javascript/api/overview/azure/identity-readme
                             {featureFlagOptions: { enabled: true }}); // load feature flags from Azure App Configuration service
const featureProvider = new ConfigurationMapFeatureFlagProvider(appConfig);
const featureManager = new FeatureManager(featureProvider);

注意

如需如何使用功能管理連結庫搭配 Azure 應用程式組態 的詳細資訊,請移至快速入門

功能旗標宣告

下列範例顯示用來在 JSON 檔案中設定功能旗標的格式。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureT",
                "enabled": true
            },
            {
                "id": "FeatureU",
                "enabled": false
            },
            {
                "id": "FeatureV",
                "enabled": true,
                "conditions": {
                    "client_filters": [
                        {
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Wed, 01 May 2019 13:59:59 GMT",
                                "End": "Mon, 01 Jul 2019 00:00:00 GMT"
                            }
                        }
                    ]
                }
            }
        ]
    }
}

feature_management 段是由慣例用來載入功能旗標設定。 feature_flags 區段是載入至程式庫的功能旗標清單。 在上一節中,我們看到三個不同的功能。 功能會使用 client_filters 屬性 (而非 conditions) 來定義其功能篩選。 在的功能篩選FeatureT中,我們看到 trueenabled 未定義任何篩選條件,因此一律會FeatureTtrue回 。 FeatureUFeatureT 相同,但 enabledfalse,導致該功能一律傳回 falseFeatureV 指定名為 Microsoft.TimeWindow 的功能篩選。 FeatureV 是可設定功能篩選的範例。 我們可以在範例中看到篩選條件具有 parameters 屬性。 parameters 屬性可用來設定篩選。 在此情況下,會設定要成為作用中功能的開始和結束時間。

您可以在這裡找到 feature_management 區段的詳細結構描述。

進階:功能旗標名稱中禁止使用冒號 ':'。

需求類型

功能旗標的 requirement_type 屬性可用來判斷篩選條件在評估功能的狀態時,是否應該使用 AnyAll 邏輯。 如果未指定 requirement_type,則預設值為 Any

  • Any 表示只有一個篩選條件需要評估為 true,即可啟用此功能。
  • All 表示每個篩選條件都必須評估為 true,才能啟用此功能。

Allrequirement_type 會變更周遊。 首先,如果沒有篩選條件,則會停用此功能。 然後,功能篩選會周遊,直到其中一個篩選條件決定應該停用功能為止。 如果沒有篩選條件表示應該停用功能,系統會將其視為已啟用。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "FeatureW",
                "enabled": true,
                "conditions": {
                    "requirement_type": "All",
                    "client_filters": [
                        {
                            "name": "Microsoft.TimeWindow",
                            "parameters": {
                                "Start": "Wed, 01 May 2019 13:59:59 GMT",
                                "End": "Mon, 01 Jul 2019 00:00:00 GMT"
                            }
                        },
                        {
                            "name": "Percentage",
                            "parameters": {
                                "Value": "50"
                            }
                        }
                    ]
                }
            },
        ]
    }
}

在上述範例中,FeatureW 指定了 Allrequirement_type,這表示其所有篩選條件都必須評估為 true,才能啟用此功能。 在此情況下,此功能會在指定的時間範圍內針對 50% 的使用者啟用。

耗用

功能管理的基本形式是檢查功能旗標是否已啟用,然後根據結果執行動作。 檢查功能旗標的狀態會透過 FeatureManagerisEnabled 方法來完成。

import { ConfigurationMapFeatureFlagProvider, FeatureManager } from "@microsoft/feature-management";
const featureProvider = new ConfigurationMapFeatureFlagProvider(config);
const featureManager = new FeatureManager(featureProvider);

const isBetaEnabled = await featureManager.isEnabled("Beta");
if (isBetaEnabled) {
    // Do something
}

實作功能篩選

建立功能篩選可讓您根據您定義的準則來啟用功能。 若要實作功能篩選,必須實作 IFeatureFilter 介面。 IFeatureFilter name具有屬性和名為 evaluate的方法。 name應該用於組態,以參考功能旗標的功能篩選。 當功能指定其可以針對功能篩選啟用時,就會呼叫 evaluate 方法。 如果 evaluate 傳回 true,表示應該啟用功能。

interface IFeatureFilter {
    name: string;
    evaluate(context: IFeatureFilterEvaluationContext, appContext?: unknown): boolean | Promise<boolean>;
}

下列代碼段示範如何實作名稱 MyCriteria為的自定義功能篩選。

    class MyCriteriaFilter {
        name = "MyCriteria";
        evaluate(context, appContext) {
            if (satisfyCriteria()) {
                return true;
            }
            else {
                return false;
            }
        }
    }

您必須在建立 FeatureManager時註冊自定義篩選。

const featureManager = new FeatureManager(ffProvider, {customFilters: [new MyCriteriaFilter()]});

參數化功能篩選

某些功能篩選需要參數來決定是否應該開啟功能。 例如,瀏覽器功能篩選可能會開啟特定一組瀏覽器的功能。 可能需要 Edge 和 Chrome 瀏覽器啟用功能,而 Firefox 則不需要。 若要這樣做,功能篩選可以設計成預期參數。 這些參數會指定於功能組態,而在程式碼中可透過 IFeatureFilter.EvaluateIFeatureFilterEvaluationContext 參數來存取。

interface IFeatureFilterEvaluationContext {
    featureName: string;
    parameters?: unknown;
}

IFeatureFilterEvaluationContext 具有名為 parameters 的屬性。 這些參數代表功能篩選可用來決定是否應該啟用功能的原始組態。 若要再次使用瀏覽器功能篩選作為範例,篩選條件可使用 parameters 擷取一組針對功能指定的允許瀏覽器,然後檢查要求是否從其中一個瀏覽器傳送。

使用應用程式內容進行功能評估

功能篩選可能需要運行時間應用程式內容來評估功能旗標。 呼叫 時 isEnabled,您可以傳入內容做為參數。

featureManager.isEnabled("Beta", { userId : "Sam" })

功能篩選器可以利用呼叫 時 isEnabled 傳入的內容。 應用程式內容會當做 的第二個參數 IFeatureFilter.Evaluate傳入。

內建功能篩選

套件隨附 FeatureManagement 兩個功能篩選: TimeWindowFilter、 和 TargetingFilter

每個內建功能篩選都有自己的參數。 以下是功能篩選清單以及範例。

Microsoft.TimeWindow

此篩選提供根據時間範圍啟用功能的功能。 如果只指定了 End,則會在該時間之前將功能視為開啟。 如果只指定了 Start,則會在該時間之後的所有時間點將功能視為開啟。

"client_filters": [
    {
        "name": "Microsoft.TimeWindow",
        "parameters": {
            "Start": "Wed, 01 May 2019 13:59:59 GMT",
            "End": "Mon, 01 Jul 2019 00:00:00 GMT"
        }
    }
]     

Microsoft.Targeting

此篩選提供為目標對象啟用功能的功能。 下列目標一節將提供目標設定的深入說明。 篩選參數包含 Audience 物件,描述使用者、群組、排除的使用者/群組,以及應該具有此功能存取權之使用者群的預設百分比。 Groups 區段中所列的每個群組物件也必須指定群組成員應具有存取權的百分比。 如果在 Exclusion 區段中指定了使用者,則無論直接或如果使用者位於排除的群組中,都會停用此功能。 否則,如果直接在 Users 區段中指定使用者,或使用者屬於任何群組推出的內含百分比,或如果使用者落入預設推出百分比,則該使用者就會啟用該功能。

"client_filters": [
    {
        "name": "Microsoft.Targeting",
        "parameters": {
            "Audience": {
                "Users": [
                    "Jeff",
                    "Alicia"
                ],
                "Groups": [
                    {
                        "Name": "Ring0",
                        "RolloutPercentage": 100
                    },
                    {
                        "Name": "Ring1",
                        "RolloutPercentage": 50
                    }
                ],
                "DefaultRolloutPercentage": 20,
                "Exclusion": {
                    "Users": [
                        "Ross"
                    ],
                    "Groups": [
                        "Ring2"
                    ]
                }
            }
        }
    }
]

目標設定

目標是功能管理策略,可讓開發人員逐漸向使用者群推出新功能。 此策略是建立在以一組稱為目標「對象」的使用者為目標的概念之上。 對象由特定使用者、群組、排除的使用者/群組和整個使用者群的指定百分比所組成。 對象中包含的群組可以進一步細分為其成員總數的百分比。

下列步驟示範新 'Beta' 功能的漸進式推出範例:

  1. 個別使用者 Jeff 和 Alicia 會被授與 Beta 的存取權。
  2. 另一位使用者 Mark 要求加入並包含在內。
  3. Beta 中包含 20% 稱為「Ring1」使用者的群組。
  4. Beta 中包含的「Ring1」用戶數目高達 100%。
  5. Beta 中包含 5% 的使用者基底。
  6. 發行百分比高達 100%,且功能已完全推出。

此推出功能的策略是透過內 含的 Microsoft.Targeting 功能篩選器,內建在連結庫中。

以目標內容為目標的使用者

目標篩選條件依賴於目標內容來評估是否應該開啟功能。 此目標內容包含資訊,例如目前正在評估的使用者,以及使用者所在的群組。 呼叫 時 isEnabled ,必須直接傳遞目標內容。

featureManager.isEnabled("Beta", { userId: "Aiden", groups: ["Ring1"] })

目標排除

定義對象時,可以從對象中排除使用者和群組。 向一組使用者推出功能時,排除非常有用,但需要從推出中排除少數使用者或群組。 排除是藉由將使用者和群組清單新增至對象的 Exclusion 屬性來定義。

"Audience": {
    "Users": [
        "Jeff",
        "Alicia"
    ],
    "Groups": [
        {
            "Name": "Ring0",
            "RolloutPercentage": 100
        }
    ],
    "DefaultRolloutPercentage": 0,
    "Exclusion": {
        "Users": [
            "Mark"
        ]
    }
}

在上述範例中,此功能會針對名為 JeffAlicia 的使用者啟用。 它也會針對名為 Ring0 的群組中的使用者啟用。 不過,如果使用者命名為 Mark,則不論使用者是否在群組 Ring0 中,都會停用此功能。 排除項目優先於目標篩選的其餘部分。

變體

將新功能新增至應用程式時,總會發生功能有多個不同的建議設計選項的情況。 決定設計的常見解決方案是某種形式的 A/B 測試,其牽涉到將功能的不同版本提供給不同區塊的使用者群,並根據使用者互動來選擇版本。 在此程式庫中,此功能是藉由代表具有變體之功能的不同組態來啟用。

變體可讓功能旗標變成不只是簡單的開啟/關閉旗標。 變體代表功能旗標的值,可以是字串、數位、布林值,甚至是組態物件。 宣告變體的功能旗標應該在應使用每個變體的情況下定義,這會在配置變體一節中更詳細地說明。

取得具有目標內容的變體

針對每個功能,可以使用 FeatureManagergetVariant 方法來擷取變體。 變異指派取決於目前正在評估的使用者,而且該資訊是從您傳入的目標內容取得。

const variant = await featureManager.getVariant("MyVariantFeatureFlag", { userId: "Sam" });

const variantName = variant.name;
const variantConfiguration = variant.configuration;

// Do something with the resulting variant and its configuration

變體功能旗標宣告

相較於一般功能旗標,變體功能旗標多了兩個屬性:variantsallocationvariants 屬性是一個數字,其中包含為這項功能定義的變體。 allocation 屬性會定義應該如何為功能配置這些變體。 就像宣告一般功能旗標一樣,您可以在 JSON 檔案中設定變體功能旗標。 以下是變體功能旗標的範例。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "enabled": true,
                "allocation": {
                    "default_when_enabled": "Small",
                    "group": [
                        {
                            "variant": "Big",
                            "groups": [
                                "Ring1"
                            ]
                        }
                    ]
                },
                "variants": [
                    { 
                        "name": "Big"
                    },  
                    { 
                        "name": "Small"
                    } 
                ]
            }
        ]
    }
}

定義變體

每個變體都有兩個屬性:名稱和組態。 此名稱是用來參考特定變體,而組態是該變體的值。 您可以使用 configuration_value 屬性來設定組態。 configuration_value 是可以是字串、數位、布林值或組態物件的內嵌組態。 如果未指定 configuration_value,所傳回變體的 configuration 屬性是 undefined

所有可能變體的清單都會針對 variants 屬性下的每個功能定義。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyVariantFeatureFlag",
                "variants": [
                    { 
                        "name": "Big", 
                        "configuration_value": {
                            "Size": 500
                        }
                    },  
                    { 
                        "name": "Small", 
                        "configuration_value": {
                            "Size": 300
                        }
                    } 
                ]
            }
        ]
    }
}

配置變體

配置功能變體的程序取決於功能的 allocation 屬性。

"allocation": { 
    "default_when_enabled": "Small", 
    "default_when_disabled": "Small",  
    "user": [ 
        { 
            "variant": "Big", 
            "users": [ 
                "Marsha" 
            ] 
        } 
    ], 
    "group": [ 
        { 
            "variant": "Big", 
            "groups": [ 
                "Ring1" 
            ] 
        } 
    ],
    "percentile": [ 
        { 
            "variant": "Big", 
            "from": 0, 
            "to": 10 
        } 
    ], 
    "seed": "13973240" 
},
"variants": [
    { 
        "name": "Big", 
        "configuration_value": "500px"
    },  
    { 
        "name": "Small", 
        "configuration_value": "300px"
    } 
]

功能的 allocation 設定具有下列屬性:

屬性 說明
default_when_disabled 指定當功能被視為停用且要求變體時,應該使用哪一個變體。
default_when_enabled 指定在功能視為已啟用時要求變體,且未將其他變體指派給使用者時,應該使用哪個變體。
user 指定變數和應為其指派該變體的使用者清單。
group 指定變體和群組清單。 如果使用者至少在其中一個群組內,則會指派變體。
percentile 指定變體和使用者計算百分比必須符合才能指派該變體的百分比範圍。
seed 計算 percentile 百分比依據的值。 如果使用相同的 seed 值,特定使用者的百分比計算在所有功能上都會相同。 如果未指定 seed,則會根據功能名稱建立預設種子。

如果未啟用此功能,功能管理員就會將標示為 default_when_disabled 的變體指派給目前使用者,在此案例中為 Small

如果啟用此功能,功能管理員將依該順序檢查 usergrouppercentile 配置,以指派變體。 在此特定範例中,如果評估的使用者名為 Marsha,則在名為 Ring1 的群組中,或使用者碰巧落在第 0 到 10 個百分位數之間,則會將指定的變異指派給使用者。 在此案例中,所有指派的使用者都會傳回 Big 變體。 如果這些配置都不相符,則會為使用者指派 default_when_enabled 變體,也就是 Small

配置邏輯與 Microsoft.Targeting 功能篩選類似,但目標中有一些參數不在配置中,反之亦然。 目標的結果與配置無關。

使用變體覆寫已啟用狀態

您可以使用變體來覆寫功能旗標的已啟用狀態。 覆寫可讓變體有機會延伸功能旗標的評估。 在具有變體的旗標上呼叫 is_enabled 時,功能管理員會檢查指派至目前使用者的變體是否已設定為覆寫結果。 覆寫會使用選擇性變體屬性 status_override 來完成。 根據預設,這個屬性會設定為 None,這表示變數不會影響旗標是否被視為已啟用或停用。 將 status_override 設定為 Enabled 可讓變數在選擇時覆寫要啟用的旗標。 將 status_override 設定為 Disabled 可提供相反的功能,因此會在選擇變體時停用旗標。 無法覆寫具有 falseenabled 狀態的功能。

如果您使用具有二進位變體的功能旗標,則 status_override 屬性會很有用。 其可讓您繼續在應用程式中使用類似於 is_enabled 的 API,同時受益於變體隨附的新功能,例如,百分位數配置和種子。

{
    "id": "MyVariantFeatureFlag",
    "enabled": true,
    "allocation": {
        "percentile": [
            {
                "variant": "On",
                "from": 10,
                "to": 20
            }
        ],
        "default_when_enabled":  "Off",
        "seed": "Enhanced-Feature-Group"
    },
    "variants": [
        {
            "name": "On"
        },
        {
            "name": "Off",
            "status_override": "Disabled"
        }
    ]
}

在上述範例中,一律會啟用功能。 如果目前使用者位於 10 到 20 的計算百分位數範圍中,則會傳回 On 變體。 否則會傳回 Off 變體,因為 status_override 等於 Disabled,而功能現在會被視為已停用。

遙測

部署功能旗標變更時,分析其對應用程式的影響通常很重要。 例如,以下是一些可能發生的問題:

  • 我的旗標是否如預期般啟用/停用?
  • 目標使用者是否如預期般可存取特定功能?
  • 特定使用者會看到哪個變體?

這些類型的問題可透過功能旗標評估事件的發出和分析來回答。

啟用遙測

根據預設,功能旗標不會發出遙測。 若要發佈指定功能旗標的遙測,旗標「必須」宣告其已針對遙測發出啟用。

針對 JSON 中定義的功能旗標,啟用會使用 telemetry 屬性來完成。

{
    "feature_management": {
        "feature_flags": [
            {
                "id": "MyFeatureFlag",
                "enabled": true,
                "telemetry": {
                    "enabled": true
                }
            }
        ]
    }
}

上述程式碼片段會定義名為 MyFeatureFlag 的功能旗標且已針對遙測啟用。 telemetry 物件的 enabled 屬性會設定為 trueenabled 屬性的值必須是 true 才能發佈旗標的遙測。

功能旗標的 telemetry 區段具有下列屬性:

屬性 說明
enabled 指定是否應該發佈功能旗標的遙測。
metadata 模型化為字典的索引鍵/值組集合,可用來將功能旗標的相關自訂中繼資料附加至評估事件。

自訂遙測發佈

您可以在建立 FeatureManager時註冊回onFeatureEvaluated呼函式。 每當評估功能旗標並針對該旗標啟用遙測時,就會呼叫此回呼。 回呼函式會將特徵評估結果當作 參數。

下列範例示範如何實作自定義回呼函式,以使用從功能評估結果擷取的資訊傳送遙測,並將其註冊至功能管理員。

const sendTelemetry = (evaluationResult) => {
    const featureId = evaluationResult.feature.id;
    const featureEnabled = evaluationResult.enabled;
    const targetingId = evaluationResult.targetingId;
    const variantName = evaluationResult.variant?.name;
    const variantAssignmentReason = evaluationResult.variantAssignmentReason;
    // custom code to send the telemetry
    // ...
}
const featureManager = new FeatureManager(featureProvider, { onFeatureEvaluated :  sendTelemtry});

Application Insights 整合

JavaScript 功能管理連結庫提供與 Application Insights SDK 整合的 延伸模組套件。

Application Insights 針對 WebNode.js案例提供不同的 SDK。 請為您的應用程式選取正確的擴充套件。

如果您的應用程式在瀏覽器中執行,請安裝 "@microsoft/feature-management-applicationinsights-browser" 套件。 下列範例示範如何建立內建 Application Insights 遙測發行者,並將其註冊至功能管理員。

import { ApplicationInsights } from "@microsoft/applicationinsights-web"
import { FeatureManager, ConfigurationObjectFeatureFlagProvider } from "@microsoft/feature-management";
import { createTelemetryPublisher, trackEvent } from "@microsoft/feature-management-applicationinsights-browser";

const appInsights = new ApplicationInsights({ config: {
    connectionString: "<APPINSIGHTS_CONNECTION_STRING>"
}});
appInsights.loadAppInsights();

const publishTelemetry = createTelemetryPublisher(appInsights);
const provider = new ConfigurationObjectFeatureFlagProvider(jsonObject);
const featureManager = new FeatureManager(provider, {onFeatureEvaluated: publishTelemetry});

// FeatureEvaluation event will be emitted when a feature flag is evaluated
featureManager.getVariant("TestFeature", {userId : TARGETING_ID}).then((variant) => { /* do something*/ });

// Emit a custom event with targeting id attached.
trackEvent(appInsights, TARGETING_ID, {name: "TestEvent"}, {"Tag": "Some Value"});

當評估已啟用遙測的功能旗標時,遙測發行者會將自定義事件傳送 FeatureEvaluation 至 Application Insights。 自定義事件遵循 FeatureEvaluationEvent 架構。

下一步

若要了解如何在應用程式中使用功能旗標,請繼續進行下列快速入門。

若要了解如何使用功能篩選,請繼續進行下列教學課程。