sql >> Database >  >> NoSQL >> MongoDB

Eenvoudige Node/Express-app, de functionele programmeermanier (Hoe om te gaan met bijwerkingen in JavaScript?)

U zult bijwerkingen niet helemaal kunnen vermijden, maar u kunt enige moeite doen om ze zoveel mogelijk weg te werken.

Het Express-framework is bijvoorbeeld inherent noodzakelijk. U voert functies uit zoals res.send() volledig voor hun bijwerkingen (de meeste tijd geeft u niet eens om de retourwaarde).

Wat u zou kunnen doen (naast het gebruik van const voor al uw aangiften, met behulp van Immutable.js datastructuren, Ramda , waarbij alle functies worden geschreven als const fun = arg => expression; in plaats van const fun = (arg) => { statement; statement; }; etc.) zou zijn om een ​​kleine abstractie te maken van hoe Express gewoonlijk werkt.

U kunt bijvoorbeeld functies maken waaraan req . moet voldoen as parameter en retourneer een object dat de responsstatus, headers en een stream bevat die als body moet worden doorgesluisd. Die functies kunnen pure functies zijn in die zin dat hun retourwaarde alleen afhangt van hun argument (het aanvraagobject), maar je zou nog steeds een wrapper nodig hebben om het antwoord daadwerkelijk te verzenden met behulp van de inherent imperatieve API van Express. Het is misschien niet triviaal, maar het kan worden gedaan.

Beschouw als voorbeeld deze functie die body als object neemt om als json te verzenden:

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

Het kan worden gebruikt om route-handlers als volgt te maken:

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

met behulp van een functie die een enkele uitdrukking retourneert zonder bijwerkingen.

Compleet voorbeeld:

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

Het antwoord testen:

$ 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}

Dit is natuurlijk maar een basisidee. Je zou de wrap() . kunnen maken functie accepteert beloften voor de retourwaarde van de functies voor asynchrone bewerkingen, maar dan zal het waarschijnlijk niet zo vrij zijn van neveneffecten:

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

en een 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 },
  }))));

Ik gebruikte .then() in plaats van async /await in de handler zelf om het er functioneler uit te laten zien, maar het kan worden geschreven als:

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

Het zou nog universeler kunnen worden gemaakt als de functie die een argument is voor wrap zou een generator zijn die in plaats van alleen beloftes op te lossen (zoals de op generatoren gebaseerde coroutines gewoonlijk doen) het zou opleveren ofwel beloften om op te lossen of chucks om te streamen, met wat verpakking om de twee te onderscheiden. Dit is slechts een basisidee, maar het kan veel verder worden uitgebreid.




  1. Redis configureren om consequent oudere gegevens eerst te verwijderen

  2. mongodb vinden door veldwaarden te vergelijken

  3. Query op MongoDB Verwijder triggers

  4. MongoDB-configuratie met node.js:Fout:kan geen verbinding maken met [localhost:27017]