sql >> Database teknologi >  >> NoSQL >> MongoDB

Simple Node/Express-app, den funktionelle programmeringsmåde (Hvordan håndterer man bivirkninger i JavaScript?)

Du vil ikke være i stand til at undgå bivirkninger helt, men du kan gøre en indsats for maksimalt at abstrahere dem væk, hvor det er muligt.

For eksempel er Express-rammen i sagens natur bydende nødvendigt. Du kører funktioner som res.send() udelukkende for deres bivirkninger (du er ikke engang ligeglad med dets returværdi det meste af tiden).

Hvad du kan gøre (ud over at bruge const for alle dine erklæringer ved at bruge Immutable.js datastrukturer, Ramda , skriver alle funktioner som const fun = arg => expression; i stedet for const fun = (arg) => { statement; statement; }; osv.) ville være at lave en lille abstraktion af, hvordan Express normalt fungerer.

For eksempel kan du oprette funktioner, der tager req som parameter og returnerer et objekt, der indeholder svarstatus, overskrifter og en strøm, der skal sendes som brødtekst. Disse funktioner kunne være rene funktioner i en forstand, at deres returværdi kun afhænger af deres argument (anmodningsobjektet), men du vil stadig have brug for noget indpakning for rent faktisk at sende svaret ved hjælp af den iboende imperative API af Express. Det er måske ikke trivielt, men det kan lade sig gøre.

Tag som et eksempel denne funktion, der tager krop som et objekt, der skal sendes som json:

const wrap = f => (req, res) => {
  const { status = 200, headers = {}, body = {} } = f(req);
  res.status(status).set(headers).json(body);
};

Det kunne bruges til at oprette rutebehandlere som denne:

app.get('/sum/:x/:y', wrap(req => ({
  headers: { 'Foo': 'Bar' },
  body: { result: +req.params.x + +req.params.y },
})));

ved hjælp af en funktion, der returnerer et enkelt udtryk uden bivirkninger.

Komplet eksempel:

const app = require('express')();

const wrap = f => (req, res) => {
  const { status = 200, headers = {}, body = {} } = f(req);
  res.status(status).set(headers).json(body);
};

app.get('/sum/:x/:y', wrap(req => ({
  headers: { 'Foo': 'Bar' },
  body: { result: +req.params.x + +req.params.y },
})));

app.listen(4444);

Test af svaret:

$ curl localhost:4444/sum/2/4 -v
* Hostname was NOT found in DNS cache
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 4444 (#0)
> GET /sum/2/4 HTTP/1.1
> User-Agent: curl/7.35.0
> Host: localhost:4444
> Accept: */*
> 
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Foo: Bar
< Content-Type: application/json; charset=utf-8
< Content-Length: 12
< ETag: W/"c-Up02vIPchuYz06aaEYNjufz5tpQ"
< Date: Wed, 19 Jul 2017 15:14:37 GMT
< Connection: keep-alive
< 
* Connection #0 to host localhost left intact
{"result":6}

Dette er selvfølgelig kun en grundlæggende idé. Du kan lave wrap() funktion accepterer løfter om returneringsværdien af ​​funktionerne for asynkrone operationer, men så vil den uden tvivl ikke være så bivirkningsfri:

const wrap = f => async (req, res) => {
  const { status = 200, headers = {}, body = {} } = await f(req);
  res.status(status).set(headers).json(body);
};

og en handler:

const delay = (t, v) => new Promise(resolve => setTimeout(() => resolve(v), t));

app.get('/sum/:x/:y', wrap(req =>
  delay(1000, +req.params.x + +req.params.y).then(result => ({
    headers: { 'Foo': 'Bar' },
    body: { result },
  }))));

Jeg brugte .then() i stedet for async /await i selve handleren for at få den til at se mere funktionel ud, men den kan skrives som:

app.get('/sum/:x/:y', wrap(async req => ({
  headers: { 'Foo': 'Bar' },
  body: { result: await delay(1000, +req.params.x + +req.params.y) },
})));

Det kunne gøres endnu mere universelt, hvis funktionen, der er et argument for at wrap ville være en generator, der i stedet for kun at give løfter om at løse (som de generator-baserede coroutines normalt gør), ville den give enten løfter om at løse eller chucks at streame, med en vis indpakning for at skelne de to. Dette er blot en grundlæggende idé, men den kan udvides meget længere.




  1. sailsjs bruger stadig standarddatabasen efter at have ændret den til mongodb

  2. Konfigurer GridFS Chunksize i MongoDB

  3. Tvetydig diskriminator 'myType' når 'myType' genereres dynamisk under kørsel

  4. Kan brugere migreres fra min mongodb-database til aws cognito-brugerpool?