MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Prosta aplikacja Node/Express, sposób programowania funkcjonalnego (Jak radzić sobie z efektami ubocznymi w JavaScript?)

Nie będziesz w stanie całkowicie uniknąć skutków ubocznych, ale możesz podjąć wysiłek, aby maksymalnie je oddzielić, jeśli to możliwe.

Na przykład struktura Express jest z natury niezbędna. Uruchamiasz funkcje takie jak res.send() całkowicie ze względu na ich skutki uboczne (przez większość czasu nawet nie dbasz o wartość zwrotu).

Co możesz zrobić (oprócz używania const dla wszystkich swoich deklaracji, używając Immutable.js struktury danych, Ramda , zapisując wszystkie funkcje jako const fun = arg => expression; zamiast const fun = (arg) => { statement; statement; }; itp.) byłoby zrobienie małej abstrakcji na temat tego, jak zwykle działa Express.

Na przykład możesz utworzyć funkcje, które pobierają req jako parametr i zwraca obiekt, który zawiera status odpowiedzi, nagłówki i strumień, który ma być przesyłany jako treść. Te funkcje mogą być czystymi funkcjami w tym sensie, że ich wartość zwracana zależy tylko od ich argumentu (obiektu żądania), ale nadal będziesz potrzebować opakowania, aby faktycznie wysłać odpowiedź za pomocą nieodłącznie niezbędnego interfejsu API Express. To może nie jest trywialne, ale można to zrobić.

Jako przykład rozważmy tę funkcję, która przyjmuje body jako obiekt do wysłania jako json:

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

Może być używany do tworzenia programów obsługi tras:

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

używając funkcji, która zwraca pojedyncze wyrażenie bez efektów ubocznych.

Pełny przykład:

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

Testowanie odpowiedzi:

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

Oczywiście to tylko podstawowy pomysł. Możesz zrobić wrap() funkcja przyjmuje obietnice wartości zwracanej przez funkcje dla operacji asynchronicznych, ale wtedy prawdopodobnie nie będzie tak wolna od skutków ubocznych:

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

i przewodnik:

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

Użyłem .then() zamiast async /await w samym module obsługi, aby wyglądał bardziej funkcjonalnie, ale można to zapisać jako:

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

Mogłoby to być jeszcze bardziej uniwersalne, gdyby funkcja będąca argumentem wrap byłby generatorem, który zamiast dawać tylko obietnice rozwiązania (jak zwykle robią to współprogramy oparte na generatorze), dawałby albo obietnice rozwiązania, albo chucks do przesyłania strumieniowego, z pewnym opakowaniem w celu rozróżnienia tych dwóch. To tylko podstawowa idea, ale można ją znacznie rozszerzyć.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Optymalizacja środowiska Linux pod kątem MongoDB

  2. Szyfruj dane Mongo w Meteorjs

  3. Uzyskaj identyfikator ostatnio wstawionego dokumentu do mongoDB ze sterownikiem Java

  4. Zalecany sposób/miejsce tworzenia indeksu w kolekcji MongoDB dla aplikacji internetowej

  5. mangusta wyraźna i wypełniona dokumentami