Azure Functions JavaScript 開發人員指南

此指南包含詳細資訊,可協助您使用 JavaScript 成功開發 Azure Functions。

身為 Express.js、Node.js 或 JavaScript 開發人員,如果您不熟悉 Azure Functions,請考慮先閱讀下列其中一篇文章:

開始使用 概念 引導式學習

JavaScript 函式基本概念

JavaScript (Node.js) 函式是匯出的 function,會在觸發時執行 (觸發程序是在 function.json 中設定)。 傳遞給每個函式的第一個引數都是 context 物件,可用來接收和傳送資料繫結、記錄,以及與執行階段進行的通訊。

資料夾結構

JavaScript 專案的必要資料夾結構如下所示。 此預設值可以變更。 如需詳細資訊,請參閱下面的 scriptFile 一節。

FunctionsProject
 | - MyFirstFunction
 | | - index.js
 | | - function.json
 | - MySecondFunction
 | | - index.js
 | | - function.json
 | - SharedCode
 | | - myFirstHelperFunction.js
 | | - mySecondHelperFunction.js
 | - node_modules
 | - host.json
 | - package.json
 | - extensions.csproj

在專案根目錄中,有共用的 host.json 檔案可用來設定函式應用程式。 每個函式都有本身程式碼檔案 (.js) 和繫結設定檔 (function.json) 的資料夾。 function.json 的父目錄名稱一律是函式的名稱。

在函式執行階段的版本 2.x 中所需的繫結擴充功能,是以 bin 資料夾中的實際程式庫檔案在 extensions.csproj 檔案中所定義。 在本機開發時,您必須註冊繫結擴充功能。 開發 Azure 入口網站中的函式時,就會為您完成這項註冊。

匯出函數

JavaScript 函式必須透過 module.exports (或 exports) 匯出。 您匯出的函式應該是可經觸發而執行的 JavaScript 函式。

根據預設,Functions 執行階段會在 index.js 中尋找您的函式,其中 index.js 與對應的 function.json 會共用相同的父目錄。 在預設情況中,您匯出的函式應該是僅來自其檔案的匯出,或是名為 runindex 的匯出。 若要設定檔案位置,並匯出函式的名稱,請參閱以下的設定您的函式進入點

您匯出的函式在執行時,會傳入多個引數。 它所採用的第一個引數一律為 context 物件。

在 2.x、3.x 或 4.x 版的 Functions 執行階段中使用 async function 宣告或純 JavaScript Promises 時,您不需要明確呼叫 context.done 回呼以表明函式已完成。 在匯出的非同步函式/Promise 完成時,函式便會完成。

下列範例說明的簡單函式會記錄其已遭到觸發,並立即完成執行。

module.exports = async function (context) {
    context.log('JavaScript trigger function processed a request.');
};

在匯出非同步函式時,您也可以將輸出繫結設定為採用 return 值。 如果您只有一個輸出繫結,建議使用此方式。

從函式傳回

若要使用 return 來指派輸出,請在 function.json 中將 name 屬性變更為 $return

{
  "type": "http",
  "direction": "out",
  "name": "$return"
}

在此情況下,您的函式會如下列範例所示:

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');
    // You can call and await an async method here
    return {
        body: "Hello, world!"
    };
}

繫結

在 JavaScript 中,繫結會設定並定義於函式的 function.json 中。 Functions 會透過數種方式與繫結互動。

輸入

在 Azure Functions 中輸入會分成兩個類別:一個是觸發程序輸入,另一個是額外的輸入。 函式可透過三種方式讀取觸發程序和其他輸入繫結 (direction === "in" 的繫結):

  • [建議] 作為參數傳至您的函式。 這些繫結會按照在 function.json 中定義的順序傳遞至函式。 function.json 中定義的 name 屬性不需要符合您的參數名稱,但最好應符合。

    module.exports = async function(context, myTrigger, myInput, myOtherInput) { ... };
    
  • 作為 context.bindings 物件的成員。 每個成員都會由 function.json 中定義的 name 屬性命名。

    module.exports = async function(context) { 
        context.log("This is myTrigger: " + context.bindings.myTrigger);
        context.log("This is myInput: " + context.bindings.myInput);
        context.log("This is myOtherInput: " + context.bindings.myOtherInput);
    };
    

輸出

函式可透過數種方式寫入輸出 (direction === "out" 的繫結)。 在所有情況下,在 function.json 中為繫結定義的 name 屬性都會對應至在您的函式中寫入的物件成員名稱。

您可以透過下列方式之一將資料指派給輸出繫結 (不要合併這些方法):

  • [建議用於多個輸出] 傳回物件。 如果您使用非同步/Promise 傳回函式,您可以傳回已指派輸出資料的物件。 在下列範例中,輸出繫結在 function.json 中會命名為 "httpResponse" 和 "queueOutput"。

    module.exports = async function(context) {
        let retMsg = 'Hello, world!';
        return {
            httpResponse: {
                body: retMsg
            },
            queueOutput: retMsg
        };
    };
    
  • [建議用於單一輸出] 直接傳回值並使用 $return 繫結名稱。 這僅適用於非同步/Promise 傳回函式。 請參閱匯出非同步函式中的範例。

  • 將值指派給 context.bindings 您可以直接將值指派給 context.bindings。

    module.exports = async function(context) {
        let retMsg = 'Hello, world!';
        context.bindings.httpResponse = {
            body: retMsg
        };
        context.bindings.queueOutput = retMsg;
    };
    

繫結資料類型

若要定義輸入繫結的資料類型,請使用繫結定義中的 dataType 屬性。 例如,若要以二進位格式讀取 HTTP 要求的內容,請使用類型 binary

{
    "type": "httpTrigger",
    "name": "req",
    "direction": "in",
    "dataType": "binary"
}

dataType 的選項是:binarystreamstring

context 物件

執行階段使用 context 物件來將資料傳遞至函式和執行階段及從中傳出。 用來從繫結讀取和設定資料,以及寫入記錄,context 物件一律是傳遞至函式的第一個參數。

module.exports = async function(context){

    // function logic goes here

    context.log("The function has executed.");
};

傳遞至函式的內容會 executionContext 公開屬性,這是具有下列屬性的物件:

屬性名稱 類型 描述
invocationId String 提供特定函式叫用的唯一識別碼。
functionName String 提供執行中函式的名稱
functionDirectory String 提供函數應用程式目錄。

下列範例會示範如何傳回 invocationId

module.exports = async function (context, req) {
    context.res = {
        body: context.executionContext.invocationId
    };
};

context.bindings 屬性

context.bindings

傳回用來讀取或指派繫結資料的具名物件。 藉由在 context.bindings 上讀取屬性,即可存取輸入和觸發程序繫結資料。 藉由將資料新增至 context.bindings,即可指派輸出繫結資料

例如,function.json 中的下列繫結定義可讓您使用 context.bindings.myOutputcontext.bindings.myInput 存取佇列的內容並且將輸出指派到佇列。

{
    "type":"queue",
    "direction":"in",
    "name":"myInput"
    ...
},
{
    "type":"queue",
    "direction":"out",
    "name":"myOutput"
    ...
}
// myInput contains the input data, which may have properties such as "name"
var author = context.bindings.myInput.name;
// Similarly, you can set your output data
context.bindings.myOutput = { 
        some_text: 'hello world', 
        a_number: 1 };

在同步函式中,您可以使用 context.done 方法選擇定義輸出繫結資料,而不使用 context.binding 物件 (如下所示)。

context.bindingData 屬性

context.bindingData

傳回包含觸發程序中繼資料和函式引動過程資料的具名物件 (invocationIdsys.methodNamesys.utcNowsys.randGuid)。 如需觸發程序中繼資料的範例,請參閱此事件中樞範例

context.done 方法

在 2.x、3.x 和 4.x 中,函式應該標示為非同步,即使函式內沒有等候的函式呼叫,而且函式不需要呼叫 coNtext.done 來表示函式的結尾。

//you don't need an awaited function call inside to use async
module.exports = async function (context, req) {
    context.log("you don't need an awaited function call inside to use async")
};

context.log 方法

context.log(message)

可讓您寫入預設追蹤層級的串流函式記錄,並且有其他記錄層級可用。 追蹤記錄會在下一節中詳細說明。

將追蹤輸出寫入記錄

在 Functions 中,您可以使用 context.log 方法,將追蹤輸出寫入記錄和主控台中。 當您呼叫 context.log() 時,會在預設追蹤層級 (也就是資訊追蹤層級) 將您的訊息寫入記錄中。 Functions 與 Azure Application Insights 整合,更妥善地擷取您的函數應用程式記錄。 Application Insights 是 Azure 監視器的一部分,提供收集、視覺化轉譯和分析應用程式遙測與追蹤輸出等功能。 若要深入了解,請參閱監視 Azure Functions

下列範例會在資訊追蹤層級寫入記錄,包括叫用識別碼:

context.log("Something has happened. " + context.invocationId); 

所有 context.log 方法都與 Node.js util.format 方法 (英文) 支援相同的參數格式。 請考慮下列程式碼,它會使用預設追蹤層級寫入函式記錄︰

context.log('Node.js HTTP trigger function processed a request. RequestUri=' + req.originalUrl);
context.log('Request Headers = ' + JSON.stringify(req.headers));

您也能以下列格式撰寫相同的程式碼:

context.log('Node.js HTTP trigger function processed a request. RequestUri=%s', req.originalUrl);
context.log('Request Headers = ', JSON.stringify(req.headers));

注意

請勿使用 console.log 來寫入追蹤輸出。 因為 console.log 的輸出是在函式應用層級擷取,所以不會繫結至特定函式叫用,也不會顯示在特定函式的記錄中。 此外,1.x 版的 Functions 執行階段不支援使用 console.log 來寫入主控台。

追蹤層級

除了預設層級之外,您還可以使用下列記錄方法,讓您在特定追蹤層級寫入函式記錄。

方法 描述
context.log.error(訊息) 將錯誤層級事件寫入記錄。
context.log.warn(訊息) 將警告層級事件寫入記錄。
context.log.info(訊息) 寫入資訊層級或更低層級的記錄。
context.log.verbose(訊息) 寫入詳細資訊層級記錄。

下列範例會在警告追蹤層級寫入相同的記錄,而不是資訊層級:

context.log.warn("Something has happened. " + context.invocationId); 

因為 error 是最高追蹤層級,所以只要啟用記錄,這項追蹤就會寫入所有追蹤層級的輸出。

設定用於記錄的追蹤層級

Functions 可讓您定義用於寫入記錄或主控台中的閾值追蹤層級。 特定閾值設定取決於您的 Functions 執行階段版本。

若要設定寫入記錄之追蹤的閾值,請使用 host.json 檔案中的 logging.logLevel 屬性。 此 JSON 物件可讓您為函數應用程式中的所有函式定義預設閾值,以及定義個別函式的特定閾值。 若要深入了解,請參閱如何設定 Azure Functions 的監視

記錄自訂遙測資料

根據預設,Functions 會將輸出寫入為 Application Insights 的追蹤。 如需更多控制,您可以改用 Application Insights Node.js SDK,將自訂遙測資料傳送至 Application Insights 執行個體。

const appInsights = require("applicationinsights");
appInsights.setup();
const client = appInsights.defaultClient;

module.exports = async function (context, req) {
    context.log('JavaScript HTTP trigger function processed a request.');

    // Use this with 'tagOverrides' to correlate custom telemetry to the parent function invocation.
    var operationIdOverride = {"ai.operation.id":context.traceContext.traceparent};

    client.trackEvent({name: "my custom event", tagOverrides:operationIdOverride, properties: {customProperty2: "custom property value"}});
    client.trackException({exception: new Error("handled exceptions can be logged with this method"), tagOverrides:operationIdOverride});
    client.trackMetric({name: "custom metric", value: 3, tagOverrides:operationIdOverride});
    client.trackTrace({message: "trace message", tagOverrides:operationIdOverride});
    client.trackDependency({target:"http://dbname", name:"select customers proc", data:"SELECT * FROM Customers", duration:231, resultCode:0, success: true, dependencyTypeName: "ZSQL", tagOverrides:operationIdOverride});
    client.trackRequest({name:"GET /customers", url:"http://myserver/customers", duration:309, resultCode:200, success:true, tagOverrides:operationIdOverride});
};

tagOverrides 參數會將 operation_Id 設為函式的引動過程識別碼。 此設定能夠讓指定的函式引動過程中所有自動產生和自訂的遙測相互關聯。

HTTP 觸發程序和繫結

HTTP 和 Webhook 觸發程序以及 HTTP 輸出繫結會使用要求和回應物件來代表 HTTP 傳訊。

要求物件

context.req (要求) 物件具有下列屬性:

屬性 描述
body 包含要求本文的物件。
headers 包含要求標頭的物件。
method 要求的 HTTP 方法。
originalUrl 要求的 URL。
params 包含要求之路由傳送參數的物件。
查詢 包含查詢參數的物件。
rawBody 字串格式的訊息內文。

回應物件

context.res (回應) 物件具有下列屬性:

屬性 描述
body 包含回應本文的物件。
headers 包含回應標頭的物件。
isRaw 表示略過回應的格式。
status 回應的 HTTP 狀態碼。
Cookie 在回應中設定的 HTTP Cookie 物件的陣列。 HTTP Cookie 物件具有 namevalue 和其他 Cookie 屬性,例如 maxAgesameSite

存取要求和回應

使用 HTTP 觸發程序時,您可以使用許多方式來存取 HTTP 要求和回應物件︰

  • context 物件的 reqres 屬性中。 如此一來,您可以使用傳統模式來存取內容物件中的 HTTP 資料,而不需使用完整 context.bindings.name 模式。 下列範例示範如何存取 context 上的 reqres 物件:

    // You can access your HTTP request off the context ...
    if(context.req.body.emoji === ':pizza:') context.log('Yay!');
    // and also set your HTTP response
    context.res = { status: 202, body: 'You successfully ordered more coffee!' }; 
    
  • 從具名輸入和輸出繫結。 如此一來,HTTP 觸發程序和繫結的運作方式會與任何其他繫結相同。 下列範例會使用具名 response 繫結來設定回應物件:

    {
        "type": "http",
        "direction": "out",
        "name": "response"
    }
    
    context.bindings.response = { status: 201, body: "Insert succeeded." };
    
  • [僅回應] 藉由呼叫context.res.send(body?: any) HTTP 回應是以做為回應主體的輸入 body 所建立。 隱含地呼叫 context.done()

  • [僅限回應] 藉由傳回回應。 $return 的特殊繫結名稱可讓您將函式的傳回值指派給輸出繫結。 下列 HTTP 輸出繫結定義 $return 輸出參數︰

    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
    

    在 2.x+ 函式中,您可以直接傳回回應物件:

    return { status: 201, body: "Insert succeeded." };
    

要求和回應索引鍵為小寫。

調整和並行

根據預設,Azure Functions 會自動監視應用程式上的負載,並視需要為 Node.js 建立其他主機執行個體。 Functions 會針對不同的觸發程序類型使用內建 (不是使用者可設定的) 閾值,以決定何時新增執行個體,例如訊息的存留期和 QueueTrigger 的佇列大小。 如需詳細資訊,請參閱耗用量和進階方案的運作方式

這種調整行為足以適用於許多 Node.js 應用程式。 針對 CPU 繫結的應用程式,您可以使用多個語言背景工作處理序進一步改善效能。

根據預設,每個 Functions 主機執行個體都有單一語言背景工作處理序。 您可以使用 FUNCTIONS_WORKER_PROCESS_COUNT 應用程式設定,來增加每個主機的背景工作處理序數目 (最多10個)。 Azure Functions 接著會嘗試在這些背景工作中平均散發同時函式叫用。 這讓 CPU 密集函式阻止其他函式執行的可能性較低。

FUNCTIONS_WORKER_PROCESS_COUNT 適用於 Functions 在擴增應用程式以符合需求時所建立的每個主機。

節點版本

下表會依作業系統,針對 Functions 執行階段的每個主要版本,顯示目前支援的 Node.js 版本:

Functions 版本 Node 版本 (Windows) Node 版本 (Linux)
4.x (建議) ~18(預覽)
~16
~14
node|18(預覽)
node|16
node|14
3.x ~14
~12
~10
node|14
node|12
node|10
2.x ~12
~10
~8
node|10
node|8
1.x 6.11.2 (由執行階段鎖定) n/a

您可以藉由從任何函式記錄 process.version,來查看執行階段目前正在使用的版本。

設定 Node 版本

針對 Windows 函數應用程式,藉由將WEBSITE_NODE_DEFAULT_VERSION應用程式設定設定為支援的 LTS 版本,例如 ~16,以 Azure 中的版本為目標。

若要深入了解 Azure Functions 執行階段支援原則,請參閱這篇文章

相依性管理

若要使用 JavaScript 程式碼中的社群程式庫,如下列範例所示,您必須確定已在 Azure 中的函數應用程式上安裝所有的相依性。

// Import the underscore.js library
const _ = require('underscore');

module.exports = async function(context) {
    // Using our imported underscore.js library
    const matched_names = _
        .where(context.bindings.myInput.names, {first: 'Carla'});
}

注意

您應該定義函式應用程式根目錄的 package.json 檔案。 定義檔案可讓應用程式中的所有函式共用相同的快取套件,以提供最佳效能。 發生版本衝突時,您可以在特定函式的資料夾中新增 package.json 檔案來解決它。

從原始檔控制部署函式應用程式時,存在於存放庫中的任何 package.json 檔案,都會在部署期間觸發其資料夾中的 npm install。 但是,在透過入口網站或 CLI 部署時,您就必須手動安裝套件。

有兩種方式可在您的函數應用程式上安裝套件:

使用相依性進行部署

  1. 執行 npm install 在本機安裝所有必要的套件。

  2. 部署您的程式碼,並確定 node_modules 資料夾包含在部署中。

使用 Kudu (僅限 Windows)

  1. 移至 https://<function_app_name>.scm.azurewebsites.net

  2. 選取 [偵錯主控台] > [CMD]。

  3. 移至 D:\home\site\wwwroot,然後將 package.json 檔案拖曳至頁面上半部的 wwwroot 資料夾。
    您也可以使用其他方法將檔案上傳至函數應用程式。 如需詳細資訊,請參閱如何更新函式應用程式檔案

  4. 上傳 package.json 檔案之後,請在 Kudu 遠端執行主控台中執行 npm install 命令。
    此動作會下載 package.json 檔案中指出的套件,並重新啟動函數應用程式。

環境變數

在本機和雲端環境中,例如作業祕密 (連接字串、金鑰和端點) 或環境設定 (例如分析變數),將您自己的環境變數新增至函數應用程式。 在函式程式碼中使用 process.env 存取這些設定。

在本機開發環境中

在本機執行時,您的函式專案會包含 local.settings.json 檔案,您可以在 Values 物件中儲存環境變數。

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "node",
    "translatorTextEndPoint": "https://api.cognitive.microsofttranslator.com/",
    "translatorTextKey": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "languageWorkers__node__arguments": "--prof"
  }
}

在 Azure 雲端環境中

在 Azure 中執行時,函數應用程式可讓您設定和使用應用程式設定,例如服務連接字串,並在執行期間將這些設定公開為環境變數。

有數種方式可供您新增、更新和刪除函式應用程式設定:

函數應用程式設定的變更需要重新啟動函數應用程式。

存取程式碼中的環境變數

使用 process.env 存取應用程式設定作為環境變數,如我們記錄 AzureWebJobsStorageWEBSITE_SITE_NAME 環境變數的第二個和第三個呼叫 context.log() 所示:

module.exports = async function (context, myTimer) {
    context.log("AzureWebJobsStorage: " + process.env["AzureWebJobsStorage"]);
    context.log("WEBSITE_SITE_NAME: " + process.env["WEBSITE_SITE_NAME"]);
};

ECMAScript 模組 (預覽)

注意

因為 ECMAScript 模組目前是 Node.js 14 和 16 Azure Functions 中的預覽功能。

ECMAScript 模組 (ES 模組) 是 Node.js 新的官方標準模組系統。 到目前為止,本文中的程式碼範例會使用 CommonJS 語法。 在 Node.js 14 或更新版本中執行 Azure Functions 時,您可以選擇使用 ES 模組語法撰寫函式。

若要在函式中使用 ES 模組,請將其檔案名稱變更為使用 .mjs 延伸模組。 下列 index.mjs 檔案範例是使用 ES 模組語法匯入 uuid 程式庫並傳回值的 HTTP 觸發函式。

import { v4 as uuidv4 } from 'uuid';

export default async function (context, req) {
    context.res.body = uuidv4();
};

設定函式進入點

function.json 屬性 scriptFileentryPoint 可用來對於匯出的函式設定位置和名稱。 如果已轉換 JavaScript,這些屬性就可能有其重要性。

使用 scriptFile

預設會從 index.js 執行 JavaScript 函式,這是與對應的 function.json 共用相同父目錄的檔案。

scriptFile 可用來取得如下列範例所示的資料夾結構:

FunctionApp
 | - host.json
 | - myNodeFunction
 | | - function.json
 | - lib
 | | - sayHello.js
 | - node_modules
 | | - ... packages ...
 | - package.json

myNodeFunctionfunction.json 應該包含 scriptFile 屬性,這個屬性指向有匯出的函式要執行的檔案。

{
  "scriptFile": "../lib/sayHello.js",
  "bindings": [
    ...
  ]
}

使用 entryPoint

scriptFile (或 index.js) 中,必須使用 module.exports 匯出函式,才能找到並執行該函式。 觸發時執行的函式預設是僅來自該檔案的匯出,名為 run 的匯出,或名為 index 的匯出。

這可以在 function.json 中使用 entryPoint 設定,如下列範例所示:

{
  "entryPoint": "logFoo",
  "bindings": [
    ...
  ]
}

在 Functions v2.x 或更新版本 (在使用者函式中支援 this 參數) 中,函式程式碼則可能如下列範例所示:

class MyObj {
    constructor() {
        this.foo = 1;
    };

    async logFoo(context) { 
        context.log("Foo is " + this.foo); 
    }
}

const myObj = new MyObj();
module.exports = myObj;

在此範例中必須注意,雖然正在匯出物件,但不保證在執行之間保留狀態。

本機偵錯

使用 --inspect 參數啟動時,Node.js 程序會接聽指定連接埠上的偵錯用戶端。 在 Azure Functions 2.x 或更新版本中,您可以藉由新增環境變數或應用程式設定 languageWorkers:node:arguments = <args>,指定引數傳入執行程式碼的Node.js 程序。

若要在本機偵錯,請在 local.settings.json 檔案中的 Values 底下新增 "languageWorkers:node:arguments": "--inspect=5858",並且將偵錯工具連結至連接埠 5858。

使用 VS Code 進行偵錯時,--inspect 參數會自動使用專案的 launch.json 檔案中的 port 值來新增。

在 1.x 版中,設定 languageWorkers:node:arguments 將無法運作。 您可以使用 Azure Functions Core Tools 上的 --nodeDebugPort 參數來選取偵錯連接埠。

注意

您只能在本機執行函數應用程式時設定 languageWorkers:node:arguments

測試

測試您的函式包括:

  • HTTP 端對端:若要從其 HTTP 端點測試函式,您可以使用可提出 HTTP 要求的任何工具,例如 cURL、Postman 或 JavaScript 的擷取方法。

  • 整合測試:整合測試包括函數應用程式層。 此測試表示您必須將參數控制到函式,包括要求和內容。 內容對每種觸發程序而言都是唯一的,表示您必須知道該觸發程序類型的傳入和傳出繫結。

    深入了解整合測試和模擬具有實驗性 GitHub 存放庫的內容層,https://github.com/anthonychu/azure-functions-test-utils

  • 單元測試:單元測試是在函數應用程式內執行。 您可以使用可測試 JavaScript 的任何工具,例如 Jest 或 Mocha。

TypeScript

當您以 2.x 版或更新版本的 Functions 執行階段為目標時,適用於 Visual Studio Code 的 Azure FunctionsAzure Functions Core Tools 可讓您使用支援 TypeScript 函數應用程式專案的範本來建立函數應用程式。 範本會產生 package.jsontsconfig.json 專案檔,讓您更輕鬆地使用這些工具從 TypeScript 程式碼轉譯、執行及發佈 JavaScript 函式。

產生的 .funcignore 檔案可用來指出專案發佈至 Azure 時,會排除哪些檔案。

TypeScript 檔案 (.ts) 會轉譯為 dist 輸出目錄中的 JavaScript 檔案 (.js)。 TypeScript 範本會使用 function.json 中的 scriptFile 參數,來指出 dist 資料夾中對應 .js 檔案的位置。 輸出位置是由範本使用 tsconfig.json 檔案中的 outDir 參數來設定。 如果您變更此設定或資料夾的名稱,執行階段就無法找到要執行的程式碼。

您在本機開發及部署 TypeScript 專案的方式取決於您的開發工具。

Visual Studio Code

適用於 Visual Studio Code 的 Azure Functions 延伸模組可讓您使用 TypeScript 開發函式。 Core Tools 是 Azure Functions 延伸模組的需求。

若要在 Visual Studio Code 中建立 TypeScript 函數應用程式,請在建立函數應用程式時選擇 TypeScript 作為語言。

當您按下 F5 在本機執行應用程式時,會在主機 (func.exe) 初始化之前完成轉譯。

當您使用 [部署至函數應用程式...] 按鈕將函數應用程式部署至 Azure 時,Azure Functions 延伸模組會先從 TypeScript 來源檔案產生已準備好用於生產環境的 JavaScript 檔案組建。

Azure Functions Core Tools

使用 Core Tools 時,TypeScript 專案與 JavaScript 專案在一些地方有所不同。

建立專案

若要使用 Core Tools 建立 TypeScript 函數應用程式專案,您必須在建立函數應用程式時指定 TypeScript 語言選項。 您可以利用下列其中一種方式來執行此作業:

  • 執行 func init 命令,選取 node 作為您的語言堆疊,然後選取 typescript

  • 執行 func init --worker-runtime typescript 命令。

執行本機

若要使用 Core Tools 在本機執行函數應用程式程式碼,請使用下列命令而不是 func host start

npm install
npm start

npm start 命令相當於下列命令:

  • npm run build
  • func extensions install
  • tsc
  • func start

發佈至 Azure

使用 func azure functionapp publish 命令部署至 Azure 之前,您可以從 TypeScript 來源檔案建立已準備好用於生產環境的 JavaScript 檔案組建。

下列命令會使用 Core Tools 準備及發佈您的 TypeScript 專案:

npm run build:production 
func azure functionapp publish <APP_NAME>

在此命令中,以您的函數應用程式名稱取代 <APP_NAME>

JavaScript 函式的考量

當您使用 JavaScript 函式時,請留意下列小節中的考量事項。

選擇單一 vCPU App Service 方案

當您建立使用 App Service 方案的函數應用程式時,建議您選取單一 vCPU 方案,而非具有多個 vCPU 的方案。 目前 Functions 在單一 vCPU VM 上執行 JavaScript 函式會較有效率,而使用較大的 VM 並不會產生預期的效能改進。 如有必要,您可以新增更多單一 vCPU VM 執行個體來手動進行擴增,或者您可以啟用自動規模調整。 如需詳細資訊,請參閱手動或自動調整執行個體計數規模

冷啟動

在無伺服器裝載模型中開發 Azure Functions 時,可進行冷啟動。 冷啟動是指函數應用程式在閒置一段時間之後進行的第一次啟動,這需要較長的時間啟動。 尤其是對於大型相依性樹狀結構的 JavaScript 函式,冷啟動可能會有很大的影響。 若要加速執行冷啟動程序,請盡可能以套件檔案的形式執行函式。 根據預設,許多部署方法都使用從套件執行的模式,但如果在進行許多冷啟動時未以此方式執行,此變更將可達到大幅改善的效果。

連線限制

當您在 Azure Functions 應用程式中使用服務特定的用戶端時,請勿在每個函式叫用中建立新的用戶端。 相反地,請在全域範圍中建立單一靜態用戶端。 如需詳細資訊,請參閱管理 Azure Functions 中的連線

使用 asyncawait

在 JavaScript 中撰寫 Azure Functions 時,您應該使用 asyncawait 關鍵字撰寫程式碼。 使用 asyncawait 撰寫程式碼,而不是使用 Promises 回呼或 .then.catch 來協助避免兩個常見問題:

  • 擲回損毀 Node.js 程序的未攔截例外狀況,可能會影響其他函式的執行。
  • 非預期的行為,例如 coNtext.log 中遺漏記錄,是由未正確等候的非同步呼叫所造成。

在下列範例中,非同步方法 fs.readFile 會以錯誤優先回呼函式作為其第二個參數來叫用。 此程式碼會造成上述兩個問題。 在正確範圍中未明確攔截到的例外狀況導致整個程序損毀 (問題 #1)。 在回呼函式範圍外呼叫 1.x context.done(),表示函式叫用可能會在讀取檔案之前結束 (問題 #2)。 在此範例中,太早呼叫 1.x context.done() 會導致從 Data from file: 開始遺漏記錄項目。

// NOT RECOMMENDED PATTERN
const fs = require('fs');

module.exports = function (context) {
    fs.readFile('./hello.txt', (err, data) => {
        if (err) {
            context.log.error('ERROR', err);
            // BUG #1: This will result in an uncaught exception that crashes the entire process
            throw err;
        }
        context.log(`Data from file: ${data}`);
        // context.done() should be called here
    });
    // BUG #2: Data is not guaranteed to be read before the Azure Function's invocation ends
    context.done();
}

使用 asyncawait 關鍵字可協助避免這兩個錯誤。 您應該使用 Node.js 公用程式函式 util.promisify,將錯誤優先回呼樣式函式轉換成可等候的函式。

在下列範例中,在函式執行期間擲回的任何未處理例外狀況,只會讓引發例外狀況的個別叫用失敗。 await 關鍵字表示只有在完成 readFile 之後,才會執行 readFileAsync 的後續步驟。 使用 asyncawait,您也不需要呼叫 context.done() 回呼。

// Recommended pattern
const fs = require('fs');
const util = require('util');
const readFileAsync = util.promisify(fs.readFile);

module.exports = async function (context) {
    let data;
    try {
        data = await readFileAsync('./hello.txt');
    } catch (err) {
        context.log.error('ERROR', err);
        // This rethrown exception will be handled by the Functions Runtime and will only fail the individual invocation
        throw err;
    }
    context.log(`Data from file: ${data}`);
}

後續步驟

如需詳細資訊,請參閱下列資源: