MongoDB
 sql >> база данни >  >> NoSQL >> MongoDB

Приложение Simple Node/Express, начинът за функционално програмиране (Как да се справя със страничните ефекти в JavaScript?)

Няма да можете да избегнете напълно страничните ефекти, но можете да положите известни усилия, за да ги абстрахирате максимално, където е възможно.

Например рамката Express е присъщо наложителна. Изпълнявате функции като res.send() изцяло за страничните им ефекти (през повечето време дори не се интересувате от неговата върната стойност).

Какво можете да направите (в допълнение към използването на const за всички ваши декларации, като използвате Immutable.js структури от данни, Ramda , записвайки всички функции като const fun = arg => expression; вместо const fun = (arg) => { statement; statement; }; и т.н.) би било да направя малко абстракция за това как Express обикновено работи.

Например можете да създадете функции, които приемат req като параметър и връща обект, който съдържа статус на отговор, заглавки и поток, който да бъде препратен като тяло. Тези функции могат да бъдат чисти функции в смисъл, че тяхната върната стойност зависи само от техния аргумент (обекта на заявката), но все пак ще ви трябва някаква обвивка, за да изпратите отговора, използвайки присъщия императивен API на Express. Може да не е тривиално, но може да се направи.

Като пример разгледайте тази функция, която приема body като обект за изпращане като json:

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

използване на функция, която връща един израз без странични ефекти.

Пълен пример:

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

Тестване на отговора:

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

Разбира се, това е само основна идея. Можете да направите wrap() функцията приема обещания за върнатата стойност на функциите за асинхронни операции, но тогава вероятно няма да бъде толкова свободна от странични ефекти:

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

и манипулатор:

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

Използвах .then() вместо async /await в самия манипулатор, за да изглежда по-функционален, но може да бъде написан като:

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

Може да стане още по-универсално, ако функцията, която е аргумент на wrap ще бъде генератор, който вместо да дава само обещания за разрешаване (както обикновено правят съпрограмите, базирани на генератор), той ще дава или обещания за разрешаване, или патронници за поточно предаване, с известно обвиване, за да се разграничат двете. Това е само основна идея, но може да бъде разширена много повече.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Много актуализации на Mongodb

  2. Вмъкнете стойност на конкретна позиция в масив в MongoDB

  3. Преобразуване на Mongo заявка в Laravel, вложен elemMatch

  4. Четене на огромна MongoDB колекция от Spark с помощта на Worker

  5. Как да ограничите максималната референция на родителския възел в mongodb