出口承诺链的快速路线方法的最佳途径?
我有一个正在被重构使用ES6承诺避免callback地狱的API路线。
在成功转换为承诺链后,我想将我的.then()
函数导出到单独的文件以保持清晰和清晰。
路线文件:
函数文件:
这工作正常。 然而,我想要做的是将在类的constructor()
函数中声明的函数移动到独立的方法,它可以引用由构造函数实例化的值。 这样一切都更好。
但是,当我这样做时,我遇到了范围问题 – this
是没有定义,等等。这样做的正确方法是什么? ES6适合在这里使用,还是应该使用其他的结构?
原始代码:
路线…
.post((req, res) => { let SubmitRouteFunctions = require('./functions/submitFunctions.js'); let fn = new SubmitRouteFunctions(req, res); // ******************************************* // ***** THIS IS WHERE THE MAGIC HAPPENS ***** // ******************************************* Promise.all([fn.redundancyCheck, fn.getLocationInfo]) .then(fn.resetRedundantID) .then(fn.constructSurveyResult) .then(fn.storeResultInDB) .then(fn.redirectToUniqueURL) .catch((err) => { console.log(err); res.send("ERROR SUBMITTING YOUR RESULT: ", err); }); })
导出函数…
module.exports = class SubmitRouteFunctions { constructor (req, res) { this.res = res; this.initialData = { answers : req.body.responses, coreFit : req.body.coreFit, secondFit : req.body.secondFit, modules : req.body.modules, }; this.newId = shortid.generate(); this.visitor = ua('UA-83723251-1', this.newId, {strictCidFormat: false}).debug(); this.clientIp = requestIp.getClientIp(req); this.redundancyCheck = mongoose.model('Result').findOne({quizId: this.newId}); this.getLocationInfo = request.get('http://freegeoip.net/json/' + this.clientIp).catch((err) => err); this.resetRedundantID = ([mongooseResult, clientLocationPromise]) => { console.log(mongooseResult); if (mongooseResult != null) { console.log('REDUNDANT ID FOUND - GENERATING NEW ONE') this.newId = shortid.generate(); this.visitor = ua('UA-83723251-1', this.newId, {strictCidFormat: false}); console.log('NEW ID: ', this.newId); }; return clientLocationPromise.data; } this.constructSurveyResult = (clientLocation) => { let additionalData = {quizId: this.newId, location: clientLocation}; return Object.assign({}, this.initialData, additionalData); } this.storeResultInDB = (newResult) => mongoose.model('Result').create(newResult).then((result) => result).catch((err) => err); this.redirectToUniqueURL = (mongooseResult) => { let parsedId = '?' + queryString.stringify({id: mongooseResult.quizId}); let customUrl = 'http://explore-your-fit.herokuapp.com/results' + parsedId; this.res.send('/results' + parsedId); } } }
备选#1:
而不是使用ES6类,执行相同的行为,清理代码只是一点点的另一种方法是导出一个匿名函数,如尼克·帕诺夫在这里所描述的: 在Node.js中,如何从我的“包含”function其他文件?
function文件:
module.exports = function (req, res) { this.initialData = { answers : req.body.responses, coreFit : req.body.coreFit, secondFit : req.body.secondFit, modules : req.body.modules, }; this.newId = shortid.generate(); this.visitor = ua('UA-83723251-1', this.newId, {strictCidFormat: false}).debug(); this.clientIp = requestIp.getClientIp(req); this.redundancyCheck = mongoose.model('Result').findOne({quizId: this.newId}); this.getLocationInfo = request.get('http://freegeoip.net/json/' + this.clientIp).catch((err) => err); this.resetRedundantID = ([mongooseResult, clientLocationPromise]) => { if (mongooseResult != null) { console.log('REDUNDANT ID FOUND - GENERATING NEW ONE') this.newId = shortid.generate(); this.visitor = ua('UA-83723251-1', this.newId, {strictCidFormat: false}); console.log('NEW ID: ', this.newId); }; return clientLocationPromise.data; } this.constructSurveyResult = (clientLocation) => { let additionalData = {quizId: this.newId, location: clientLocation}; return Object.assign({}, this.initialData, additionalData); } this.storeResultInDB = (newResult) => mongoose.model('Result').create(newResult).then((result) => result).catch((err) => err); this.redirectToUniqueURL = (mongooseResult) => { let parsedId = '?' + queryString.stringify({id: mongooseResult.quizId}); let customUrl = 'http://explore-your-fit.herokuapp.com/results' + parsedId; res.send('/results' + parsedId); } }
虽然这并不能避免为每个方法添加this.someFn()...
,正如我最初所想的那样,但它在路由文件中需要额外的步骤 – 这样做可以避免我必须分配一个特定的名称空间方法。
path文件
.post((req, res) => { require('./functions/submitFunctions_2.js')(req, res); Promise.all([redundancyCheck, getLocationInfo]) .then(resetRedundantID) .then(constructSurveyResult) .then(storeResultInDB) .then(redirectToUniqueURL) .catch((err) => { console.log(err); res.send("ERROR SUBMITTING YOUR RESULT: ", err); }); })
这些函数被重置,以反映每个新的req
和res
对象POST请求命中路由,并且this
关键字明显绑定到每个导入的方法的POST路由callback。
重要提示:您无法使用此方法导出箭头function。 导出的函数必须是传统的匿名函数。 这就是为什么每个Udo G对同一个主题的评论:
值得注意的是,这是有效的,因为函数中的这个函数是直接调用函数的全局函数 (不受任何限制)。
替代scheme2:
另一种select,由Bergi提供: 如何使用箭头函数(公共类字段)作为类的方法?
我正在寻找的是一个实验性的function….
有一个build议可能允许你省略构造函数(),并直接把这个赋值放在具有相同function的类作用域中,但是我不推荐使用它,因为它是高度实验性的。
但是,还有一种方法可以将这些方法分开:
或者,您可以使用.bind,它允许您在原型上声明方法,然后将其绑定到构造函数中的实例。 这种方法具有更大的灵活性,因为它允许从课堂外修改方法。
基于Bergi的例子:
module.exports = class SomeClass { constructor() { this.someMethod= this.someMethod.bind(this); this.someOtherMethod= this.someOtherMethod.bind(this); … } someMethod(val) { // Do something with val } someOtherMethod(val2) { // Do something with val2 } }
显然,这更符合我最初寻找的内容,因为它增强了导出代码的整体可读性。 但是这样做需要你像我最初那样为你的路由文件中的新类指定一个命名空间:
let SubmitRouteFunctions = require('./functions/submitFunctions.js'); let fn = new SubmitRouteFunctions(req, res); Promise.all([fn.redundancyCheck, fn.getLocationInfo]) .then(...)
build议/实验特点:
这不是我的舵手 ,但是根据Bergi ,目前有一个Stage-2提议( https://github.com/tc39/proposal-class-public-fields )试图让“类实例字段”被添加到下一个ES规格。
“类实例字段”描述旨在存在于类的实例上的属性(并且可以可选地包括用于所述属性的初始化expression式)
据我所知,这将完全解决这里描述的问题,通过允许附加到class
对象的方法引用它自己的每个实例。 因此, this
问题会消失,方法可以自动绑定。
我(有限的)理解是箭头函数将被用来完成这个,就像这样:
class SomeClass { constructor() {...} someMethod (val) => { // Do something with val // Where 'this' is bound to the current instance of SomeClass } }
显然这可以使用Babel编译器来完成,但显然是实验性和风险性的。 另外,在这种情况下,我们试图在Node / Express中这样做,这几乎是一个毫无意义的问题:)