Zoeken…


Invoering

Node is een programmeertaal waarin alles asynchroon kan worden uitgevoerd. Hieronder vindt u enkele voorbeelden en de typische dingen van asynchroon werken.

Syntaxis

  • doSomething ([args], function ([argsCB]) {/ * doe iets als u klaar bent * /});
  • doSomething ([args], ([argsCB]) => {/ * doe iets als u klaar bent * /});

Terugbel functies

Callback-functies in JavaScript

Callback-functies zijn gebruikelijk in JavaScript. Terugbelfuncties zijn mogelijk in JavaScript omdat functies eersteklas burgers zijn .

Synchrone callbacks.

Terugbelfuncties kunnen synchroon of asynchroon zijn. Omdat asynchrone terugbelfuncties complexer kunnen zijn, is hier een eenvoudig voorbeeld van een synchrone terugbelfunctie.

// a function that uses a callback named `cb` as a parameter
function getSyncMessage(cb) {
    cb("Hello World!");
}

console.log("Before getSyncMessage call");
// calling a function and sending in a callback function as an argument.
getSyncMessage(function(message) {
    console.log(message);
});
console.log("After getSyncMessage call");

De output voor de bovenstaande code is:

> Before getSyncMessage call
> Hello World!
> After getSyncMessage call

Eerst zullen we doorlopen hoe de bovenstaande code wordt uitgevoerd. Dit is meer voor degenen die het concept van callbacks nog niet begrijpen, als u het al begrijpt, kunt u deze paragraaf overslaan. Eerst wordt de code ontleed en dan is het eerste interessante wat er gebeurt is dat regel 6 wordt uitgevoerd die uitgangen Before getSyncMessage call de console Before getSyncMessage call . Vervolgens wordt regel 8 uitgevoerd die de functie getSyncMessage en een anonieme functie verzendt als argument voor de parameter met de naam cb in de functie getSyncMessage . De uitvoering vindt nu plaats in de functie getSyncMessage op regel 3 die de functie cb uitvoert die zojuist is doorgegeven. Deze aanroep verzendt een argumentstring "Hallo wereld" voor het param-benoemde message in de anonieme doorgegeven functie. De uitvoering gaat dan naar regel 9 die Hello World! registreert Hello World! naar de console. Vervolgens gaat de uitvoering door het proces van het verlaten van de callstack ( zie ook ) door regel 10 te raken en vervolgens regel 4 en uiteindelijk terug naar regel 11.

Enkele informatie over callbacks in het algemeen:

  • De functie die u als terugbelopdracht naar een functie verzendt, kan nul keer, één keer of meerdere keren worden genoemd. Het hangt allemaal af van de implementatie.
  • De terugbelfunctie kan synchroon of asynchroon en mogelijk zowel synchroon als asynchroon worden genoemd.
  • Net als normale functies zijn de namen die u parameters geeft voor uw functie niet belangrijk, maar de volgorde is. Dus bijvoorbeeld op lijn 8 de parameter message had kunnen worden genoemd statement , msg , of als u dat onzinnig iets als jellybean . U moet dus weten welke parameters naar uw callback worden verzonden, zodat u ze in de juiste volgorde met de juiste namen kunt krijgen.

Asynchrone callbacks.

Een ding op te merken over Javascript is dat het synchroon standaard, maar er zijn API's die in het milieu (browser, Node.js, etc.) die het kon laten asynchrone (er is meer daarover hier ).

Enkele veel voorkomende dingen die asynchroon zijn in JavaScript-omgevingen die callbacks accepteren:

  • Evenementen
  • setTimeout
  • setInterval
  • de ophaal-API
  • Promises

Elke functie die een van de bovenstaande functies gebruikt, kan ook worden ingepakt met een functie die wordt teruggebeld en de terugbelactie zou dan een asynchrone terugbelactie zijn (hoewel het inpakken van een belofte met een functie die teruggebeld wordt waarschijnlijk als een antipatroon wordt beschouwd als er zijn meer geprefereerde manieren om beloften af te handelen).

Dus gezien die informatie kunnen we een asynchrone functie bouwen vergelijkbaar met de bovenstaande synchrone functie.

// a function that uses a callback named `cb` as a parameter
function getAsyncMessage(cb) {
    setTimeout(function () { cb("Hello World!") }, 1000);
}

console.log("Before getSyncMessage call");
// calling a function and sending in a callback function as an argument.
getAsyncMessage(function(message) {
    console.log(message);
});
console.log("After getSyncMessage call");

Hiermee wordt het volgende naar de console afgedrukt:

> Before getSyncMessage call
> After getSyncMessage call
// pauses for 1000 ms with no output
> Hello World!

De uitvoering van de lijn gaat naar de logs van regel 6 "Voordat getSyncMessage-aanroep". Vervolgens gaat de uitvoering naar regel 8 die getAsyncMessage aanroept met een callback voor de param cb . Vervolgens wordt regel 3 uitgevoerd die setTimeout aanroept met een callback als het eerste argument en het getal 300 als het tweede argument. setTimeout doet wat het doet en houdt die callback vast zodat het het later in 1000 milliseconden kan oproepen, maar na het instellen van de time-out en voordat het de 1000 milliseconden pauzeert, geeft het de uitvoering terug naar waar het was gestopt, zodat het naar regel 4 gaat , dan lijn 11, en dan pauzeert gedurende 1 seconde en setTimeout roept vervolgens de callback functie die uitvoering terug naar lijn 3, waar neemt getAsyncMessages callback wordt aangeroepen met de waarde "Hello World" voor zijn parameter message die vervolgens naar de console is aangemeld op lijn 9 .

Callback-functies in Node.js

NodeJS heeft asynchrone callbacks en levert gewoonlijk twee parameters voor uw functies, die soms conventioneel err en data . Een voorbeeld van het lezen van een bestandstekst.

const fs = require("fs");

fs.readFile("./test.txt", "utf8", function(err, data) {
    if(err) {
        // handle the error 
    } else {
        // process the file text given with data
    }
});

Dit is een voorbeeld van een callback die eenmalig wordt genoemd.

Het is een goede gewoonte om op de een of andere manier met de fout om te gaan, ook al logt u hem gewoon in of gooit u hem. De rest is niet nodig als je gooit of terugkeert en kan worden verwijderd om de inspringing te verminderen zolang je de uitvoering van de huidige functie in het if stopt door iets te doen zoals gooien of terugkeren.

Hoewel het gebruikelijk om te zien kunnen zijn err , data kan niet altijd het geval dat uw callbacks dat patroon is het het beste om te kijken naar documentatie gebruiken.

Een ander voorbeeld van een callback komt uit de expressbibliotheek (express 4.x):

// this code snippet was on http://expressjs.com/en/4x/api.html
const express = require('express');
const app = express();

// this app.get method takes a url route to watch for and a callback
// to call whenever that route is requested by a user.
app.get('/', function(req, res){
  res.send('hello world');
});

app.listen(3000);

Dit voorbeeld toont een callback die meerdere keren wordt aangeroepen. De terugbelactie is voorzien van twee objecten als params die hier worden aangeduid als req en res Deze namen komen overeen met respectievelijk verzoek en antwoord, en ze bieden manieren om het binnenkomende verzoek te bekijken en het antwoord in te stellen dat naar de gebruiker zal worden verzonden.

Zoals u kunt zien, zijn er verschillende manieren waarop een callback kan worden gebruikt om sync- en async-code in JavaScript uit te voeren en callbacks zijn overal in JavaScript alomtegenwoordig.

Code voorbeeld

Vraag: Wat is de output van onderstaande code en waarom?

setTimeout(function() {
    console.log("A");
}, 1000);

setTimeout(function() {
    console.log("B");
}, 0);

getDataFromDatabase(function(err, data) {
    console.log("C");
    setTimeout(function() {
        console.log("D");
    }, 1000);
});

console.log("E");

Output: dit is zeker bekend: EBAD . C is onbekend wanneer het zal worden vastgelegd.

Verklaring: De compiler stopt niet op de getDataFromDatabase setTimeout en getDataFromDatabase . Dus de eerste regel die hij zal loggen is E De callback-functies (eerste argument van setTimeout ) worden na de ingestelde time-out asynchroon uitgevoerd!

Meer details:

  1. E heeft geen setTimeout
  2. B heeft een ingestelde time-out van 0 milliseconden
  3. A heeft een ingestelde time-out van 1000 milliseconden
  4. D moet een database aanvragen, nadat deze D 1000 milliseconden moet wachten, zodat deze na A komt.
  5. C is onbekend omdat het onbekend is wanneer de gegevens van de database worden opgevraagd. Het kan voor of na A .

Async foutafhandeling

Proberen te vangen

Fouten moeten altijd worden behandeld. Als u synchroon programmeren gebruikt, kunt u een try catch . Maar dit werkt niet als u asynchroon werkt! Voorbeeld:

try {
    setTimeout(function() {
        throw new Error("I'm an uncaught error and will stop the server!");
    }, 100); 
}
catch (ex) {
    console.error("This error will not be work in an asynchronous situation: " + ex);
}

Async-fouten worden alleen binnen de callback-functie afgehandeld!

Werk mogelijkheden

v0.8

Event handlers

De eerste versies van Node.JS hebben een gebeurtenishandler.

process.on("UncaughtException", function(err, data) { 
    if (err) {
        // error handling
    }
});
v0.8

domeinen

Binnen een domein worden de fouten vrijgegeven via de event-emitters. Door dit te gebruiken worden alle fouten, timers, callback-methoden impliciet alleen geregistreerd binnen het domein. Door een fout, stuur een fout en stuur de applicatie niet.

var domain = require("domain");
var d1 = domain.create();
var d2 = domain.create();

d1.run(function() {
    d2.add(setTimeout(function() {
        throw new Error("error on the timer of domain 2");
    }, 0));
});

d1.on("error", function(err) {
    console.log("error at domain 1: " + err);
});

d2.on("error", function(err) {
    console.log("error at domain 2: " + err);
});

Terugbellen hel

Callback hell (ook een piramide van doom of boemerangeffect) ontstaat wanneer u te veel callback-functies in een callback-functie nestelt. Hier is een voorbeeld om een bestand te lezen (in ES6).

const fs = require('fs');
let filename = `${__dirname}/myfile.txt`;

fs.exists(filename, exists => {
    if (exists) {
        fs.stat(filename, (err, stats) => {
            if (err) {
                throw err;
            }
            if (stats.isFile()) {
                fs.readFile(filename, null, (err, data) => {
                    if (err) {
                        throw err;
                    }
                    console.log(data);
                });
            }
            else {
                throw new Error("This location contains not a file");
            }
        });
    }
    else {
        throw new Error("404: file not found");
    }
}); 

Hoe "Callback Hell" te voorkomen

Het wordt aanbevolen om niet meer dan 2 callback-functies te nesten. Dit zal u helpen om de leesbaarheid van de code te behouden en zal mij in de toekomst veel gemakkelijker te onderhouden zijn. Als u meer dan 2 callbacks wilt nesten, probeer dan in plaats daarvan gedistribueerde gebeurtenissen te gebruiken.

Er bestaat ook een bibliotheek genaamd async die helpt bij het beheren van callbacks en de uitvoering ervan beschikbaar op npm. Het verhoogt de leesbaarheid van callback-code en geeft u meer controle over uw callback-codestroom, inclusief de mogelijkheid om ze parallel of in serie uit te voeren.

Inheemse beloften

v6.0.0

Beloften zijn een hulpmiddel voor async-programmering. In JavaScript staan beloften bekend om hun then methoden. Beloften hebben twee hoofdstaten 'in behandeling' en 'geregeld'. Als een belofte eenmaal 'geregeld' is, kan deze niet meer teruggaan naar 'in behandeling'. Dit betekent dat beloften meestal goed zijn voor evenementen die maar één keer voorkomen. De 'gevestigde' staat heeft ook twee staten 'opgelost' en 'afgewezen'. U kunt een nieuwe belofte maken met behulp van het new trefwoord en een functie doorgeven aan de new Promise(function (resolve, reject) {}) de constructor new Promise(function (resolve, reject) {}) .

De functie die wordt doorgegeven aan de Promise-constructor ontvangt altijd een eerste en tweede parameter die meestal respectievelijk resolve en reject genoemd. De naamgeving van deze twee parameters is een conventie, maar ze zullen de belofte in de 'opgeloste' staat of de 'afgewezen' staat brengen. Wanneer een van deze twee wordt genoemd, gaat de belofte van 'in behandeling' naar 'geregeld'. resolve wordt aangeroepen wanneer de gewenste actie, die vaak asynchroon is, is uitgevoerd en reject wordt gebruikt als de actie een fout heeft gemaakt.

In de onderstaande time-out staat een functie die een belofte retourneert.

function timeout (ms) {
  return new Promise(function (resolve, reject) {
    setTimeout(function () {
      resolve("It was resolved!");
    }, ms)
  });
}

timeout(1000).then(function (dataFromPromise) {
  // logs "It was resolved!"
  console.log(dataFromPromise);
})

console.log("waiting...");

console uitgang

waiting...
// << pauses for one second>>
It was resolved!

Wanneer de time-out wordt aangeroepen, wordt de functie die is doorgegeven aan de Promise-constructor onmiddellijk uitgevoerd. Vervolgens wordt de methode setTimeout uitgevoerd en wordt de callback in de volgende ms milliseconden geactiveerd, in dit geval ms=1000 . Omdat de callback naar setTimeout nog niet is geactiveerd, geeft de time-outfunctie de besturing terug aan het aanroepbereik. De keten then werkwijzen worden dan opgeslagen om later te worden opgeroepen wanneer / indien de belofte is opgelost. Als er catch methoden hier zouden ze worden opgeslagen als goed, maar zou worden ontslagen wanneer / als de belofte 'uitval'.

Het script drukt vervolgens 'wachten ...' af. Een seconde later roept de setTimeout zijn callback aan die de oplossingsfunctie oproept met de string "Het was opgelost!". Die string wordt vervolgens doorgegeven aan de callback van de then methode en vervolgens vastgelegd in de gebruiker.

Op dezelfde manier kunt u de asynchrone setTimeout-functie omwikkelen waarvoor een callback nodig is. U kunt elke asynchrone actie met een belofte omwikkelen.

Lees meer over beloften in de JavaScript-documentatie Beloften .



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow