Przewodnik dla deweloperów usługi Azure Functions pracujących w języku JavaScript

Ten przewodnik zawiera szczegółowe informacje ułatwiające pomyślne opracowywanie Azure Functions przy użyciu języka JavaScript.

Jeśli jesteś Azure Functions nowym deweloperem Express.js, Node.js lub JavaScript, rozważ przeczytanie jednego z następujących artykułów:

Wprowadzenie Pojęcia Nauka z przewodnikiem

Podstawy funkcji języka JavaScript

Funkcja JavaScript (Node.js) jest eksportowaną function funkcją, która jest wykonywana po wyzwoleniu (wyzwalacze są konfigurowane w pliku function.json). Pierwszym argumentem przekazywanym context do każdej funkcji jest obiekt, który służy do odbierania i wysyłania danych powiązania, rejestrowania i komunikowania się ze środowiskiem uruchomieniowym.

Struktura folderów

Wymagana struktura folderów dla projektu JavaScript wygląda następująco. Tę wartość domyślną można zmienić. Aby uzyskać więcej informacji, zobacz sekcję scriptFile poniżej.

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

W katalogu głównym projektu znajduje się udostępniony plik host.json , który może służyć do konfigurowania aplikacji funkcji. Każda funkcja ma folder z własnym plikiem kodu (.js) i plikiem konfiguracji powiązania (function.json). Nazwa katalogu nadrzędnego function.jsonjest zawsze nazwą funkcji.

Rozszerzenia powiązań wymagane w wersji 2.x środowiska uruchomieniowego usługi Functions są definiowane w extensions.csproj pliku z rzeczywistymi plikami biblioteki w folderze bin . Podczas tworzenia aplikacji lokalnie należy zarejestrować rozszerzenia powiązań. Podczas opracowywania funkcji w Azure Portal ta rejestracja jest wykonywana za Ciebie.

Eksportowanie funkcji

Funkcje języka JavaScript muszą być eksportowane za pośrednictwem metody module.exports (lub exports). Wyeksportowana funkcja powinna być funkcją Języka JavaScript wykonywaną po wyzwoleniu.

Domyślnie środowisko uruchomieniowe usługi Functions wyszukuje funkcję w index.jspliku , gdzie index.js współudzieli ten sam katalog nadrzędny co odpowiadający mu function.jsonelement . W domyślnym przypadku wyeksportowana funkcja powinna być jedynym eksportem z pliku lub eksportu o nazwie run lub index. Aby skonfigurować lokalizację pliku i nazwę eksportu funkcji, przeczytaj o konfigurowaniu punktu wejścia funkcji poniżej.

Wyeksportowana funkcja jest przekazywana szereg argumentów podczas wykonywania. Pierwszy argument, który przyjmuje, jest zawsze obiektem context .

W przypadku korzystania z async function deklaracji lub zwykłych obietnic języka JavaScript w wersji 2.x, 3.x lub 4.x środowiska uruchomieniowego usługi Functions nie trzeba jawnie wywoływać context.done wywołania zwrotnego, aby zasygnalizować, że funkcja została ukończona. Funkcja zostanie ukończona po zakończeniu eksportowania funkcji asynchronicznego/obietnicy.

Poniższy przykład to prosta funkcja, która rejestruje, czy została wyzwolona, i natychmiast kończy wykonywanie.

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

Podczas eksportowania funkcji asynchronicznych można również skonfigurować powiązanie wyjściowe, aby pobrać return wartość. Jest to zalecane, jeśli masz tylko jedno powiązanie wyjściowe.

Zwracanie z funkcji

Aby przypisać dane wyjściowe przy użyciu polecenia return, zmień name właściwość na $return w function.jsonpliku .

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

W takim przypadku funkcja powinna wyglądać podobnie do następującego przykładu:

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!"
    };
}

Powiązania

W języku JavaScript powiązania są konfigurowane i definiowane w pliku function.json funkcji. Funkcje współdziałają z powiązaniami na wiele sposobów.

Dane wejściowe

Dane wejściowe są podzielone na dwie kategorie w Azure Functions: jeden jest wejściem wyzwalacza, a drugi jest dodatkowymi danymi wejściowymi. Wyzwalacz i inne powiązania wejściowe (powiązania direction === "in") mogą być odczytywane przez funkcję na trzy sposoby:

  • [Zalecane] W miarę przekazywania parametrów do funkcji. Są one przekazywane do funkcji w tej samej kolejności, w której są zdefiniowane w pliku function.json. Właściwość zdefiniowana name w pliku function.json nie musi być zgodna z nazwą parametru, chociaż powinna.

    module.exports = async function(context, myTrigger, myInput, myOtherInput) { ... };
    
  • Jako elementy członkowskie context.bindings obiektu. Każdy element członkowski jest nazwany przez właściwość zdefiniowaną name w pliku function.json.

    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);
    };
    

Dane wyjściowe

Dane wyjściowe (powiązania direction === "out"elementu ) mogą być zapisywane przez funkcję na wiele sposobów. We wszystkich przypadkach name właściwość powiązania zdefiniowana w pliku function.json odpowiada nazwie elementu członkowskiego obiektu zapisanego w funkcji.

Dane można przypisać do powiązań wyjściowych w jeden z następujących sposobów (nie należy łączyć tych metod):

  • [Zalecane w przypadku wielu danych wyjściowych] Zwracanie obiektu. Jeśli używasz funkcji zwracanej async/Promise, możesz zwrócić obiekt z przypisanymi danymi wyjściowymi. W poniższym przykładzie powiązania wyjściowe mają nazwy "httpResponse" i "queueOutput" w pliku function.json.

    module.exports = async function(context) {
        let retMsg = 'Hello, world!';
        return {
            httpResponse: {
                body: retMsg
            },
            queueOutput: retMsg
        };
    };
    
  • [Zalecane w przypadku pojedynczych danych wyjściowych] Zwracanie wartości bezpośrednio i użycie nazwy powiązania $return. Działa to tylko w przypadku funkcji zwracanych przez funkcję asynchroniową/obietnicę. Zobacz przykład eksportowania funkcji asynchronicznych.

  • Przypisywanie wartości do context.bindings Wartości można przypisywać bezpośrednio do pliku context.bindings.

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

Typ danych powiązań

Aby zdefiniować typ danych dla powiązania wejściowego, użyj dataType właściwości w definicji powiązania. Aby na przykład odczytać zawartość żądania HTTP w formacie binarnym, użyj typu binary:

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

dataType Dostępne opcje to: binary, streami string.

obiekt kontekstu

Środowisko uruchomieniowe używa context obiektu do przekazywania danych do i z funkcji i środowiska uruchomieniowego. Służy do odczytywania i ustawiania danych z powiązań oraz zapisywania w dziennikach context , obiekt jest zawsze pierwszym parametrem przekazywanym do funkcji.

module.exports = async function(context){

    // function logic goes here

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

Kontekst przekazany do funkcji uwidacznia executionContext właściwość, która jest obiektem o następujących właściwościach:

Nazwa właściwości Typ Opis
invocationId Ciąg Zawiera unikatowy identyfikator wywołania określonej funkcji.
functionName Ciąg Zawiera nazwę uruchomionej funkcji
functionDirectory Ciąg Udostępnia katalog aplikacji funkcji.

W poniższym przykładzie pokazano, jak zwrócić element invocationId.

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

właściwość context.bindings

context.bindings

Zwraca nazwany obiekt używany do odczytywania lub przypisywania danych powiązania. Dostęp do danych wejściowych i wyzwalaczy powiązania można uzyskać, odczytując właściwości w witrynie context.bindings. Dane powiązania wyjściowego można przypisać, dodając dane do context.bindings

Na przykład następujące definicje powiązań w pliku function.json umożliwiają dostęp do zawartości kolejki z context.bindings.myInput i przypisywanie danych wyjściowych do kolejki przy użyciu polecenia context.bindings.myOutput.

{
    "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 };

W funkcji synchronicznej można zdefiniować dane powiązania wyjściowego context.done przy użyciu metody zamiast context.binding obiektu (zobacz poniżej).

context.bindingData, właściwość

context.bindingData

Zwraca nazwany obiekt zawierający metadane wyzwalacza i dane wywołania funkcji (invocationId, sys.methodName, sys.utcNow, sys.randGuid). Przykład metadanych wyzwalacza można znaleźć w tym przykładzie usługi Event Hubs.

context.done, metoda

W wersji 2.x, 3.x i 4.x funkcja powinna być oznaczona jako asynchronizna, nawet jeśli w funkcji nie ma oczekiwanego wywołania funkcji, a funkcja nie musi wywoływać funkcji context.done, aby wskazać koniec funkcji.

//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, metoda

context.log(message)

Umożliwia zapisywanie w dziennikach funkcji przesyłania strumieniowego na domyślnym poziomie śledzenia z innymi dostępnymi poziomami rejestrowania. Rejestrowanie śledzenia zostało szczegółowo opisane w następnej sekcji.

Zapisywanie danych wyjściowych śledzenia w dziennikach

W usłudze Functions metody służą context.log do zapisywania danych wyjściowych śledzenia w dziennikach i konsoli programu . Po wywołaniu context.log()metody komunikat jest zapisywany w dziennikach na domyślnym poziomie śledzenia, który jest poziomem śledzenia informacji . Usługa Functions integruje się z usługą aplikacja systemu Azure Insights, aby lepiej przechwytywać dzienniki aplikacji funkcji. Usługa Application Insights, część usługi Azure Monitor, udostępnia funkcje zbierania, renderowania wizualnego i analizy danych telemetrycznych aplikacji oraz danych wyjściowych śledzenia. Aby dowiedzieć się więcej, zobacz monitorowanie Azure Functions.

Poniższy przykład zapisuje dziennik na poziomie śledzenia informacji, w tym identyfikator wywołania:

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

Wszystkie context.log metody obsługują ten sam format parametrów obsługiwany przez metodę Node.js util.format. Rozważmy następujący kod, który zapisuje dzienniki funkcji przy użyciu domyślnego poziomu śledzenia:

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

Możesz również napisać ten sam kod w następującym formacie:

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

Uwaga

Nie używaj console.log polecenia do zapisywania danych wyjściowych śledzenia. Ponieważ dane wyjściowe z console.log polecenia są przechwytywane na poziomie aplikacji funkcji, nie są powiązane z wywołaniem określonej funkcji i nie są wyświetlane w dziennikach określonej funkcji. Ponadto wersja 1.x środowiska uruchomieniowego usługi Functions nie obsługuje zapisywania w konsoli przy użyciu polecenia console.log .

Poziomy śledzenia

Oprócz poziomu domyślnego dostępne są następujące metody rejestrowania, które umożliwiają zapisywanie dzienników funkcji na określonych poziomach śledzenia.

Metoda Opis
context.log.error(message) Zapisuje zdarzenie na poziomie błędu w dziennikach.
context.log.warn(message) Zapisuje zdarzenie na poziomie ostrzeżenia do dzienników.
context.log.info(wiadomość) Zapisy do rejestrowania na poziomie informacji lub niższe.
context.log.verbose(message) Zapisy do pełnego rejestrowania na poziomie.

Poniższy przykład zapisuje ten sam dziennik na poziomie śledzenia ostrzeżenia zamiast poziomu informacji:

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

Ponieważ błąd jest najwyższym poziomem śledzenia, ten ślad jest zapisywany w danych wyjściowych na wszystkich poziomach śledzenia, o ile rejestrowanie jest włączone.

Konfigurowanie poziomu śledzenia na potrzeby rejestrowania

Funkcje umożliwiają zdefiniowanie poziomu śledzenia progu do zapisywania w dziennikach lub konsoli. Określone ustawienia progowe zależą od wersji środowiska uruchomieniowego usługi Functions.

Aby ustawić próg śladów zapisanych w dziennikach, użyj logging.logLevel właściwości w pliku host.json. Ten obiekt JSON umożliwia zdefiniowanie domyślnego progu dla wszystkich funkcji w aplikacji funkcji oraz zdefiniowanie określonych progów dla poszczególnych funkcji. Aby dowiedzieć się więcej, zobacz How to configure monitoring for Azure Functions (Jak skonfigurować monitorowanie dla Azure Functions).

Rejestrowanie telemetrii niestandardowej

Domyślnie usługa Functions zapisuje dane wyjściowe jako ślady w usłudze Application Insights. Zamiast tego możesz użyć zestawu SDK usługi Application Insights Node.js do wysyłania niestandardowych danych telemetrycznych do wystąpienia usługi 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});
};

Parametr tagOverrides ustawia parametr operation_Id na identyfikator wywołania funkcji. To ustawienie umożliwia skorelowanie wszystkich automatycznie generowanych i niestandardowych danych telemetrycznych dla danej wywołania funkcji.

Wyzwalacze i powiązania HTTP

Wyzwalacze HTTP i element webhook oraz powiązania wyjściowe HTTP używają obiektów żądań i odpowiedzi do reprezentowania komunikatów HTTP.

Obiekt żądania

Obiekt context.req (request) ma następujące właściwości:

Właściwość Opis
ciało Obiekt, który zawiera treść żądania.
Nagłówki Obiekt, który zawiera nagłówki żądania.
metoda Metoda HTTP żądania.
originalUrl Adres URL żądania.
params Obiekt, który zawiera parametry routingu żądania.
zapytanie Obiekt, który zawiera parametry zapytania.
rawBody Treść wiadomości jako ciąg.

Obiekt odpowiedzi

context.res Obiekt (response) ma następujące właściwości:

Właściwość Opis
ciało Obiekt, który zawiera treść odpowiedzi.
Nagłówki Obiekt, który zawiera nagłówki odpowiedzi.
isRaw Wskazuje, że formatowanie jest pomijane dla odpowiedzi.
stan Kod stanu HTTP odpowiedzi.
Pliki cookie Tablica obiektów plików cookie HTTP ustawionych w odpowiedzi. Obiekt pliku cookie HTTP ma namewłaściwości , valuei inne pliki cookie, takie jak maxAge lub sameSite.

Uzyskiwanie dostępu do żądania i odpowiedzi

Podczas pracy z wyzwalaczami HTTP można uzyskać dostęp do obiektów żądania HTTP i odpowiedzi na wiele sposobów:

  • Właściwości i res z req obiektu context . W ten sposób można użyć konwencjonalnego wzorca, aby uzyskać dostęp do danych HTTP z obiektu kontekstu, zamiast używać pełnego context.bindings.name wzorca. W poniższym przykładzie pokazano, jak uzyskać dostęp do req obiektów i res w obiekcie context:

    // 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!' }; 
    
  • Z nazwanych powiązań wejściowych i wyjściowych. W ten sposób wyzwalacz HTTP i powiązania działają tak samo jak inne powiązania. Poniższy przykład ustawia obiekt odpowiedzi przy użyciu nazwanego response powiązania:

    {
        "type": "http",
        "direction": "out",
        "name": "response"
    }
    
    context.bindings.response = { status: 201, body: "Insert succeeded." };
    
  • [Tylko odpowiedź] Przez wywołanie metody context.res.send(body?: any). Odpowiedź HTTP jest tworzona z danymi wejściowymi body jako treścią odpowiedzi. context.done() jest wywoływana niejawnie.

  • [Tylko odpowiedź] Zwracając odpowiedź. Specjalna nazwa $return powiązania umożliwia przypisanie wartości zwracanej funkcji do powiązania wyjściowego. Następujące powiązanie danych wyjściowych HTTP definiuje $return parametr wyjściowy:

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

    W funkcji 2.x+ można bezpośrednio zwrócić obiekt odpowiedzi:

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

Klucze żądań i odpowiedzi mają małe litery.

Skalowanie i współbieżność

Domyślnie Azure Functions automatycznie monitoruje obciążenie aplikacji i tworzy dodatkowe wystąpienia hosta dla Node.js zgodnie z potrzebami. Usługa Functions używa wbudowanych (nie konfigurowalnych przez użytkownika) progów dla różnych typów wyzwalaczy, aby zdecydować, kiedy dodać wystąpienia, takie jak wiek komunikatów i rozmiar kolejki dla funkcji QueueTrigger. Aby uzyskać więcej informacji, zobacz Jak działają plany Zużycie i Premium.

To zachowanie skalowania jest wystarczające dla wielu aplikacji Node.js. W przypadku aplikacji powiązanych z procesorem CPU można zwiększyć wydajność, korzystając z wielu procesów roboczych języka.

Domyślnie każde wystąpienie hosta usługi Functions ma pojedynczy proces roboczy języka. Można zwiększyć liczbę procesów roboczych na hosta (do 10) przy użyciu ustawienia aplikacji FUNCTIONS_WORKER_PROCESS_COUNT . Azure Functions następnie próbuje równomiernie dystrybuować równoczesne wywołania funkcji między tymi procesami roboczymi. Zmniejsza to prawdopodobieństwo, że funkcja intensywnie korzystająca z procesora CPU blokuje działanie innych funkcji.

FUNCTIONS_WORKER_PROCESS_COUNT dotyczy każdego hosta tworzonego przez usługę Functions podczas skalowania aplikacji w celu spełnienia wymagań.

Wersja węzła

W poniższej tabeli przedstawiono bieżące obsługiwane wersje Node.js dla każdej wersji głównej środowiska uruchomieniowego usługi Functions według systemu operacyjnego:

Wersja usługi Functions Wersja środowiska Node (Windows) Wersja środowiska Node (Linux)
4.x (zalecane) ~16
~14
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 (zablokowane przez środowisko uruchomieniowe) n/d

Możesz zobaczyć bieżącą wersję używaną przez środowisko uruchomieniowe, logując się process.version z dowolnej funkcji.

Ustawianie wersji środowiska Node

W przypadku aplikacji funkcji systemu Windows należy określić wersję docelową na platformie Azure, ustawiając WEBSITE_NODE_DEFAULT_VERSIONustawienie aplikacji na obsługiwaną wersję LTS, taką jak ~16.

Aby dowiedzieć się więcej na temat zasad obsługi środowiska uruchomieniowego Azure Functions, zapoznaj się z tym artykułem.

Zarządzanie zależnościami

Aby korzystać z bibliotek społeczności w kodzie JavaScript, jak pokazano w poniższym przykładzie, musisz upewnić się, że wszystkie zależności są zainstalowane w aplikacji funkcji na platformie 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'});
}

Uwaga

Należy zdefiniować package.json plik w katalogu głównym aplikacji funkcji. Zdefiniowanie pliku umożliwia wszystkim funkcjom w aplikacji współużytkowanie tych samych buforowanych pakietów, co zapewnia najlepszą wydajność. Jeśli wystąpi konflikt wersji, możesz go rozwiązać, dodając package.json plik w folderze określonej funkcji.

Podczas wdrażania aplikacji funkcji z kontroli źródła dowolny package.json plik znajdujący się w repozytorium wyzwoli npm install element w folderze podczas wdrażania. Jednak podczas wdrażania za pośrednictwem portalu lub interfejsu wiersza polecenia należy ręcznie zainstalować pakiety.

Istnieją dwa sposoby instalowania pakietów w aplikacji funkcji:

Wdrażanie za pomocą zależności

  1. Zainstaluj wszystkie wymagane pakiety lokalnie, uruchamiając polecenie npm install.

  2. Wdróż kod i upewnij się, że node_modules folder jest uwzględniony we wdrożeniu.

Korzystanie z usługi Kudu (tylko system Windows)

  1. Przejdź do witryny https://<function_app_name>.scm.azurewebsites.net.

  2. Wybierz pozycjęCmD konsoli >debugowania.

  3. Przejdź do D:\home\site\wwwrootstrony , a następnie przeciągnij plik package.json do folderu wwwroot w górnej połowie strony.
    Możesz również przekazywać pliki do aplikacji funkcji na inne sposoby. Aby uzyskać więcej informacji, zobacz Jak zaktualizować pliki aplikacji funkcji.

  4. Po przekazaniu pliku package.json uruchom npm install polecenie w konsoli zdalnego wykonywania Kudu.
    Ta akcja powoduje pobranie pakietów wskazanych w pliku package.json i ponowne uruchomienie aplikacji funkcji.

Zmienne środowiskowe

Dodaj własne zmienne środowiskowe do aplikacji funkcji, zarówno w środowiskach lokalnych, jak i w chmurze, takich jak wpisy tajne operacyjne (parametry połączenia, klucze i punkty końcowe) lub ustawienia środowiska (takie jak zmienne profilowania). Uzyskaj dostęp do tych ustawień przy użyciu process.env w kodzie funkcji.

W lokalnym środowisku projektowym

W przypadku uruchamiania lokalnego local.settings.jsonprojekt funkcji zawiera plik, w którym zmienne środowiskowe są przechowywane w Values obiekcie .

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

W środowisku chmury platformy Azure

Podczas uruchamiania na platformie Azure aplikacja funkcji umożliwia ustawianie i używanie ustawień aplikacji, takich jak parametry połączenia usługi, i uwidacznianie tych ustawień jako zmiennych środowiskowych podczas wykonywania.

Istnieje kilka sposobów dodawania, aktualizowania i usuwania ustawień aplikacji funkcji:

Zmiany ustawień aplikacji funkcji wymagają ponownego uruchomienia aplikacji funkcji.

Uzyskiwanie dostępu do zmiennych środowiskowych w kodzie

Uzyskaj dostęp do ustawień aplikacji jako zmiennych środowiskowych przy użyciu polecenia process.env, jak pokazano tutaj w drugim i trzecim wywołaniu, w context.log() którym rejestrujemy AzureWebJobsStorage zmienne środowiskowe i :WEBSITE_SITE_NAME

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

Moduły ECMAScript (wersja zapoznawcza)

Uwaga

Ponieważ moduły ECMAScript są obecnie funkcją w wersji zapoznawczej w Node.js 14 i 16 Azure Functions.

Moduły ECMAScript (moduły ES) to nowy oficjalny standardowy system modułów dla Node.js. Do tej pory przykłady kodu w tym artykule używają składni CommonJS. Podczas uruchamiania Azure Functions w systemie Node.js 14 lub nowszym możesz pisać funkcje przy użyciu składni modułów ES.

Aby użyć modułów ES w funkcji, zmień jego nazwę pliku, aby użyć .mjs rozszerzenia. Poniższy przykład pliku index.mjs to funkcja wyzwalana przez protokół HTTP, która używa składni modułów ES do importowania uuid biblioteki i zwracania wartości.

import { v4 as uuidv4 } from 'uuid';

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

Konfigurowanie punktu wejścia funkcji

Właściwości function.jsonscriptFile i entryPoint mogą służyć do konfigurowania lokalizacji i nazwy wyeksportowanej funkcji. Te właściwości mogą być ważne, gdy kod JavaScript jest transpilowany.

Korzystanie z akcji scriptFile

Domyślnie funkcja JavaScript jest wykonywana z index.jspliku , który współudzieli ten sam katalog nadrzędny co odpowiadający mu function.jsonelement .

scriptFile Może służyć do pobierania struktury folderów, która wygląda jak w poniższym przykładzie:

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

Element for function.jsonmyNodeFunction powinien zawierać właściwość wskazującą scriptFile plik z wyeksportowaną funkcją do uruchomienia.

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

Korzystanie z akcji entryPoint

W scriptFile (lub index.js) funkcja musi zostać wyeksportowana przy użyciu polecenia module.exports , aby można było je odnaleźć i uruchomić. Domyślnie funkcja wykonywana po wyzwoleniu jest jedynym eksportem z tego pliku, eksportem o nazwie lub eksportem o nazwie runindex.

Można to skonfigurować przy użyciu polecenia entryPoint w programie , function.jsonjak w poniższym przykładzie:

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

W systemie Functions w wersji 2.x lub nowszej this , która obsługuje parametr w funkcjach użytkownika, kod funkcji może być następujący:

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

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

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

W tym przykładzie należy pamiętać, że chociaż obiekt jest eksportowany, nie ma gwarancji zachowania stanu między wykonaniami.

Debugowanie lokalne

Po rozpoczęciu od parametru --inspect proces Node.js nasłuchuje klienta debugowania na określonym porcie. W Azure Functions wersji 2.x lub nowszej można określić argumenty, które mają być przekazywane do procesu Node.js, który uruchamia kod, dodając zmienną środowiskową lub ustawienie languageWorkers:node:arguments = <args>aplikacji .

Aby debugować lokalnie, dodaj "languageWorkers:node:arguments": "--inspect=5858" element Values w pliku local.settings.json i dołącz debuger do portu 5858.

Podczas debugowania przy użyciu programu VS Code --inspect parametr jest automatycznie dodawany przy użyciu port wartości w pliku launch.json projektu.

W wersji 1.x ustawienie languageWorkers:node:arguments nie będzie działać. Port debugowania można wybrać przy użyciu parametru --nodeDebugPort w narzędziach Azure Functions Core Tools.

Uwaga

Konfigurację można skonfigurować languageWorkers:node:arguments tylko podczas lokalnego uruchamiania aplikacji funkcji.

Testowanie

Testowanie funkcji obejmuje:

  • End-to-end protokołu HTTP: aby przetestować funkcję z poziomu punktu końcowego HTTP, możesz użyć dowolnego narzędzia, które może wysyłać żądanie HTTP, takie jak cURL, Postman lub metoda pobierania języka JavaScript.

  • Testowanie integracji: test integracji obejmuje warstwę aplikacji funkcji. Ten test oznacza, że musisz kontrolować parametry w funkcji, w tym żądanie i kontekst. Kontekst jest unikatowy dla każdego rodzaju wyzwalacza i oznacza, że musisz znać powiązania przychodzące i wychodzące dla tego typu wyzwalacza.

    Dowiedz się więcej na temat testowania integracji i pozorowania warstwy kontekstu za pomocą eksperymentalnego repozytorium GitHub. https://github.com/anthonychu/azure-functions-test-utils

  • Testowanie jednostkowe: testy jednostkowe są wykonywane w aplikacji funkcji. Możesz użyć dowolnego narzędzia, które może przetestować język JavaScript, na przykład Jest lub Mocha.

TypeScript

W przypadku środowiska uruchomieniowego usługi Functions w wersji docelowej w wersji 2.x lub nowszej zarówno Azure Functions dla Visual Studio Code, jak i Azure Functions Core Tools umożliwiają tworzenie aplikacji funkcji przy użyciu szablonu obsługującego projekty aplikacji funkcji TypeScript. Szablon generuje package.json i tsconfig.json pliki projektu, które ułatwiają transpilowanie, uruchamianie i publikowanie funkcji JavaScript z poziomu kodu TypeScript za pomocą tych narzędzi.

Wygenerowany .funcignore plik służy do wskazywania, które pliki są wykluczone po opublikowaniu projektu na platformie Azure.

Pliki TypeScript (ts) są transpilowane do plików JavaScript (.js) w katalogu wyjściowym dist . Szablony typeScript używają parametruscriptFile w pliku , function.json aby wskazać lokalizację odpowiedniego pliku .js w folderzedist. Lokalizacja wyjściowa jest ustawiana przez szablon przy użyciu outDir parametru tsconfig.json w pliku . Jeśli zmienisz to ustawienie lub nazwę folderu, środowisko uruchomieniowe nie będzie mogło odnaleźć kodu do uruchomienia.

Sposób lokalnego opracowywania i wdrażania z projektu TypeScript zależy od narzędzia programistycznego.

Visual Studio Code

Rozszerzenie Azure Functions dla Visual Studio Code umożliwia opracowywanie funkcji przy użyciu języka TypeScript. Narzędzia Core Tools są wymagane przez rozszerzenie Azure Functions.

Aby utworzyć aplikację funkcji TypeScript w Visual Studio Code, wybierz TypeScript język podczas tworzenia aplikacji funkcji.

Po naciśnięciu klawisza F5 , aby uruchomić aplikację lokalnie, transpilacja jest wykonywana przed zainicjowanie hosta (func.exe).

Podczas wdrażania aplikacji funkcji na platformie Azure przy użyciu przycisku Wdróż w aplikacji funkcji... rozszerzenie Azure Functions najpierw generuje gotową do produkcji kompilację plików JavaScript z plików źródłowych TypeScript.

Azure Functions Core Tools

Istnieje kilka sposobów, w jaki projekt TypeScript różni się od projektu JavaScript podczas korzystania z narzędzi Core Tools.

Tworzenie projektu

Aby utworzyć projekt aplikacji funkcji TypeScript przy użyciu narzędzi Core Tools, należy określić opcję języka TypeScript podczas tworzenia aplikacji funkcji. Można to zrobić w jeden z następujących sposobów:

  • func init Uruchom polecenie, wybierz jako node stos języka, a następnie wybierz pozycję typescript.

  • Uruchom polecenie func init --worker-runtime typescript.

Uruchamianie lokalne

Aby uruchomić kod aplikacji funkcji lokalnie przy użyciu narzędzi Core Tools, użyj następujących poleceń zamiast func host start:

npm install
npm start

Polecenie npm start jest równoważne z następującymi poleceniami:

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

Publikowanie na platformie Azure

Przed użyciem func azure functionapp publish polecenia do wdrożenia na platformie Azure należy utworzyć gotową do produkcji kompilację plików JavaScript z plików źródłowych języka TypeScript.

Następujące polecenia przygotowują i publikują projekt TypeScript przy użyciu narzędzi Core Tools:

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

W tym poleceniu zastąp <APP_NAME> ciąg nazwą aplikacji funkcji.

Zagadnienia dotyczące funkcji języka JavaScript

Podczas pracy z funkcjami języka JavaScript należy pamiętać o zagadnieniach w poniższych sekcjach.

Wybieranie planów App Service z jednym procesorem wirtualnym

Podczas tworzenia aplikacji funkcji korzystającej z planu App Service zalecamy wybranie planu pojedynczego procesora wirtualnego zamiast planu z wieloma procesorami wirtualnymi. Obecnie usługa Functions uruchamia funkcje języka JavaScript wydajniej na maszynach wirtualnych z pojedynczym procesorem wirtualnym, a użycie większych maszyn wirtualnych nie powoduje oczekiwanych ulepszeń wydajności. W razie potrzeby możesz ręcznie skalować w poziomie, dodając kolejne wystąpienia maszyn wirtualnych z pojedynczym procesorem wirtualnym lub możesz włączyć skalowanie automatyczne. Aby uzyskać więcej informacji, zobacz Ręczne lub automatyczne skalowanie liczby wystąpień.

Zimny start

Podczas opracowywania Azure Functions w modelu hostingu bezserwerowego zimne starty są rzeczywistością. Zimny start odnosi się do faktu, że uruchomienie aplikacji funkcji po raz pierwszy po okresie braku aktywności trwa dłużej. W przypadku funkcji Języka JavaScript z dużymi drzewami zależności może być istotne. Aby przyspieszyć proces zimnego uruchamiania, uruchom funkcje jako plik pakietu , jeśli to możliwe. Wiele metod wdrażania używa domyślnie przebiegu z modelu pakietów, ale jeśli występują duże zimne starty i nie są uruchomione w ten sposób, ta zmiana może zaoferować znaczną poprawę.

Limity połączeń

W przypadku korzystania z klienta specyficznego dla usługi w aplikacji Azure Functions nie należy tworzyć nowego klienta z każdym wywołaniem funkcji. Zamiast tego utwórz pojedynczego, statycznego klienta w zakresie globalnym. Aby uzyskać więcej informacji, zobacz zarządzanie połączeniami w Azure Functions.

Używanie i asyncawait

Podczas pisania Azure Functions w języku JavaScript należy napisać kod przy użyciu async słów kluczowych i await . Pisanie kodu przy użyciu instrukcji async i await zamiast wywołań zwrotnych lub .then i .catch z obietnicami pomaga uniknąć dwóch typowych problemów:

  • Zgłaszanie niechwyconych wyjątków, które powodują awarię procesu Node.js, co może mieć wpływ na wykonywanie innych funkcji.
  • Nieoczekiwane zachowanie, takie jak brakujące dzienniki z kontekstu.log spowodowane wywołaniami asynchronicznymi, które nie są prawidłowo oczekiwane.

W poniższym przykładzie metoda fs.readFile asynchroniczna jest wywoływana z funkcją wywołania zwrotnego pierwszego błędu jako jej drugi parametr. Ten kod powoduje oba wymienione powyżej problemy. Wyjątek, który nie został jawnie przechwycony w prawidłowym zakresie, uległ awarii całego procesu (problem nr 1). Wywołanie 1.x context.done() poza zakresem funkcji wywołania zwrotnego oznacza, że wywołanie funkcji może zakończyć się przed odczytaniem pliku (problem nr 2). W tym przykładzie wywołanie 1.x context.done() zbyt wcześnie powoduje brakujących wpisów dziennika rozpoczynających się od 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();
}

async Użycie słów kluczowych i await pomaga uniknąć obu tych błędów. Należy użyć funkcji util.promisify narzędzia Node.js, aby przekształcić funkcje typu wywołania zwrotnego typu "pierwszy błąd" w funkcje oczekujące.

W poniższym przykładzie wszystkie nieobsługiwane wyjątki zgłoszone podczas wykonywania funkcji kończą się niepowodzeniem tylko w przypadku pojedynczego wywołania, które zgłosiło wyjątek. Słowo await kluczowe oznacza, że kroki wykonywane readFileAsync tylko po readFile zakończeniu. W systemach async i awaitnie trzeba również wywoływać wywołania zwrotnego 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}`);
}

Następne kroki

Więcej informacji można znaleźć w następujących zasobach: