- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试为“可链接的”Express.js 验证编写一个模块:
const validatePost = (req, res, next) => {
validator.validate(req.body)
.expect('name.first')
.present('The parameter is required')
.string('The parameter must be a string')
.go(next);
};
router.post('/', validatePost, (req, res, next) => {
return res.send('Validated!');
});
validator.validate
的代码(为简洁起见进行了简化):
const validate = (data) => {
let validation;
const expect = (key) => {
validation.key = key;
// Here I get the actual value, but for testing purposes of .present() and
// .string() chainable methods it returns a random value from a string,
// not string and an undefined
validation.value = [ 'foo', 123, void 0 ][Math.floor(Math.random() * 3)];
return validation;
};
const present = (message) => {
if (typeof validation.value === 'undefined') {
validation.valid = false;
validation.errors.push({ key: validation.key, message: message });
}
return validation;
};
const string = (message) => {
if (typeof validation.value !== 'string') {
validation.valid = false;
validation.errors.push({ key: validation.key, message: message });
}
return validation;
};
const go = (next) => {
if (!validation.valid) {
let error = new Error('Validation error');
error.name = 'ValidationError';
error.errors = validation.errors;
// I even wrap async callbacks in process.nextTick()
process.nextTick(() => next(error));
}
process.nextTick(next);
};
validation = {
valid: true,
data: data,
errors: [],
expect: expect,
present: present,
string: string,
go: go
};
return validation;
};
该代码适用于短链,返回正确的错误对象。但是,如果我链接了很多方法,请说:
const validatePost = (req, res, next) => {
validator.validate(req.body)
.expect('name.first')
.present('The parameter is required')
.string('The parameter must be a string')
.expect('name.first') // Same for testing
.present('The parameter is required')
.string('The parameter must be a string')
// [...] 2000 times
.go(next);
};
Node.js 抛出 RangeError: Maximum call stack size exceeded
。请注意,我将异步回调 .go(next)
包装在 process.nextTick()
中。
最佳答案
我没有太多时间看这个,但我确实注意到了一个相当大的问题。当 !validator.valid
为 true
时,您有一个单分支 if 语句导致 next
被调用两次 .一般来说,单分支 if
语句是一种代码味道。
这可能不是您遇到堆栈溢出的原因,但它可能是罪魁祸首。
(代码更改以粗体显示)
const go = (next) => {
if (!validation.valid) {
let error = new Error('Validation error');
error.name = 'ValidationError';
error.errors = validation.errors;
process.nextTick(() => next(error));
}
<b>else {</b>
process.nextTick(next);
<b>}</b>
};
有些人也使用 return
来欺骗 if
。这也行,但很烂
const go = (next) => {
if (!validation.valid) {
let error = new Error('Validation error');
error.name = 'ValidationError';
error.errors = validation.errors;
process.nextTick(() => next(error));
<b>return;</b> // so that the next line doesn't get called too
}
process.nextTick(next);
};
我认为整个go
函数这样表达更好...
const go = (next) => {
// `!` is hard to reason about
// place the easiest-to-understand, most-likely-to-happen case first
if (validation.valid) {
process.nextTick(next)
}
// very clear if/else branching
// there are two possible outcomes and one block of code for each
else {
let error = new Error('Validation error');
error.name = 'ValidationError';
error.errors = validation.errors;
// no need to create a closure here
<del>process.nextTick(() => next(error));</del>
<b>process.nextTick(next, error);</b>
}
};
其他备注
您的代码中还有其他单分支 if
语句
const present = (message) => {
if (typeof validation.value === 'undefined') {
// this branch only performs mutations and doesn't return anything
validation.valid = false;
validation.errors.push({ key: validation.key, message: message });
}
// there is no `else` branch ...
return validation;
};
这个不那么令人反感,但我仍然认为,一旦您欣赏了总是带有 else
的 if
语句,就更难推理了。考虑强制两个分支的三元运算符 (?:
)。还要考虑像 Scheme 这样的语言,其中在使用 if
时始终需要 True 和 False 分支。
这是我编写present
函数的方式
const present = (message) => {
if (validation.value === undefined) {
// True branch returns
return Object.assign(validation, {
valid: false,
errors: [...validation.errors, { key: validation.key, message }]
})
}
else {
// False branch returns
return validation
}
};
这是一个自以为是的评论,但我认为它值得考虑。当您必须返回此代码并稍后阅读时,您会感谢我。当然,一旦您的代码采用这种格式,您就可以对其进行加糖以删除大量语法样板
const present = message =>
validation.value === undefined
<b>?</b> Object.assign(validation, {
valid: false,
errors: [...validation.errors, { key: validation.key, message }]
})
<b>:</b> validation
优点
return
有效地强制您在函数中使用单个表达式——这意味着您不能(轻易地)使函数过于复杂if
没有返回值,所以使用三元可以很好地处理隐式返回true
和 false
分支,以便您始终处理 both谓词是的,没有什么能阻止您使用 ()
将多个表达式组合成一个,但关键不是要将每个函数简化为一个表达式——它更像是一种理想的和漂亮的在它工作时使用。如果在任何时候您觉得可读性受到影响,您可以求助于 if (...) { return ... } else { return ... }
以获得熟悉且友好的语法/样式。
关于javascript - Node.js — 超过最大调用堆栈大小,即使使用 process.nextTick(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40945955/
当在代码中更新了数据,并希望等到对应的Dom更新之后,再执行一些逻辑。这时,我们就会用到$nextTick ?
我是 Vue js 新手,我试图理解方法中使用 nextTick 的逻辑。所以我有两个这样的组件: IsTuruIslem.vue ... ... .
如果我有这样的代码: class SomeClass constructor: -> @someAttr = false someFunction: -> process.ne
我正在尝试测试我的应用程序在连续两次 tick 上发生的情况。这是我目前所拥有的(测试在 karma devtools 中失败,但在命令行中失败): import { mount } from 'av
我偶然发现了一个函数( here on SO ),它可以写入文件,但确保不会覆盖文件: function writeFile(i){ var i = i || 0; var fileN
我有一个 我有一个已安装的方法,可以在其中初始化 map 。 mounted(){ this.map = L.map(this.mapId, { preferCanvas: true }).setV
尝试递归调用同步函数来解析数组的元素;一旦到达数组的最后一个元素,就会调用回调。但是,当传递给 process.nextTick 时,回调被认为是未定义的,因为在与回调相同的范围内声明的另一个变量会打
我有一个 50k 条目的列表,我正在输入我的数据库。 var tickets = [new Ticket(), new Ticket(), ...]; // 50k of them tickets.f
下面的程序会在 NodeJS 中挂起,有人知道为什么吗? ended = false;events = require('events');eventEmitter = new events.Even
Node.js 版本 0.10 今天发布,并引入了 setImmediate。 API changes文档建议在执行递归 nextTick 调用时使用它。 来自什么MDN says它看起来与proce
我应该多久或何时使用 process.nextTick ? 我明白它的目的(主要是因为 this 和 this )。 根据经验,当我必须调用回调时,我总是使用它。这是一般方法还是还有其他方法? 此外,
更新:事实证明这是一个非常愚蠢的问题。我只是没有注意到引用的示例中的一些简单的事情。 我一直在查看有关滴答声和事件循环的信息,大部分内容都很清楚,但 the nextTick documentatio
下面是“practise01.js”文件中的代码, function fn(name){ return f; function f(){ var n = name;
Node.js 0.10 版今天发布,引入了setImmediate。 API changes文档建议在进行递归 nextTick 调用时使用它。 来自MDN says它似乎与 process.nex
我读过 nextTick 允许在下一个操作中执行代码。但这在我的代码中不起作用,有人可以帮助我吗?请纠正我。谢谢。 .vue ..... methods:{ getUserInfo(){
使用 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/EventLoop 中的视觉表示: setImmediate() 和
我从人们那里得到的印象是...除非与 process.nextTick 一起使用,否则所有 JavaScript 函数都是同步的。什么时候使用它最好? 我想确保我不会在不需要它的地方过度使用它。在这一
无论好坏,我们 stub process.nextTick 以同步调用它的第一个参数(回调)。看代码: global.test_clock = sinon.useFakeTimers(); sinon
我正在尝试测试此 site 中找到的 Yahoo API。但是,我可以获得“请求 token ”,但我似乎不知道如何继续,因为我的应用程序抛出 process.nextTick 错误 此外,如果可能的
我遇到了这个express.js路线,它是 small example in its official repo 的一部分,演示如何处理错误,看看: app.get('/next', function
我是一名优秀的程序员,十分优秀!