आप पूरी तरह से दुष्प्रभावों से बचने में सक्षम नहीं होंगे, लेकिन जहां संभव हो, आप उन्हें दूर करने के लिए कुछ प्रयास कर सकते हैं।
उदाहरण के लिए एक्सप्रेस ढांचा स्वाभाविक रूप से अनिवार्य है। आप res.send()
. जैसे फ़ंक्शन चलाते हैं पूरी तरह से उनके दुष्प्रभावों के लिए (आप ज्यादातर समय इसके वापसी मूल्य की भी परवाह नहीं करते हैं)।
आप क्या कर सकते हैं (const
. का उपयोग करने के अलावा Immutable.js
का उपयोग करके अपनी सभी घोषणाओं के लिए डेटा संरचनाएं, Ramda
, सभी कार्यों को const fun = arg => expression;
इसके बजाय const fun = (arg) => { statement; statement; };
आदि) एक्सप्रेस आमतौर पर कैसे काम करता है, इस पर थोड़ा सा विचार करना होगा।
उदाहरण के लिए आप ऐसे फ़ंक्शन बना सकते हैं जो req
. लेते हैं पैरामीटर के रूप में और उस ऑब्जेक्ट को वापस करें जिसमें प्रतिक्रिया स्थिति, शीर्षलेख और स्ट्रीम को शरीर के रूप में पाइप किया जाना है। वे कार्य इस अर्थ में शुद्ध कार्य हो सकते हैं कि उनका वापसी मूल्य केवल उनके तर्क (अनुरोध वस्तु) पर निर्भर करता है लेकिन एक्सप्रेस के स्वाभाविक अनिवार्य एपीआई का उपयोग करके वास्तव में प्रतिक्रिया भेजने के लिए आपको अभी भी कुछ रैपर की आवश्यकता होगी। यह मामूली नहीं हो सकता है लेकिन यह किया जा सकता है।
एक उदाहरण के रूप में इस फ़ंक्शन पर विचार करें जो शरीर को जेसन के रूप में भेजने के लिए एक वस्तु के रूप में लेता है:
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()
बना सकते हैं फ़ंक्शन async oprations के लिए फ़ंक्शन के वापसी मूल्य के लिए वादे स्वीकार करता है, लेकिन तब यह यकीनन इतना दुष्प्रभाव मुक्त नहीं होगा:
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
. का तर्क है एक जनरेटर होगा जो केवल हल करने का वादा करता है (जैसे जनरेटर-आधारित कोरआउट आमतौर पर करते हैं) यह या तो हल करने का वादा करता है या स्ट्रीम करने के लिए चक देता है, दोनों को अलग करने के लिए कुछ रैपिंग के साथ। यह सिर्फ एक बुनियादी विचार है लेकिन इसे और भी आगे बढ़ाया जा सकता है।