JavaScript封装Bootstrap校验函数时如何让forEach先执行完再返回
核心问题说明
执行顺序颠倒和forEach是否执行完成无关:forEach遍历本身是同步执行的,但是你在遍历中给表单绑定的submit事件回调属于异步触发逻辑,只有当表单的提交事件被实际触发时才会执行,因此函数外层的打印逻辑会在绑定完所有事件监听器后立刻执行,早于提交事件触发后的回调逻辑。
同时你当前的bsvalidate函数仅完成了「给表单绑定提交校验规则」的操作,并没有当场执行校验,因此直接返回校验状态永远只能拿到初始值。
解决方案
根据使用场景不同有两种实现方式:
场景1:调用函数时当场校验所有表单,同步返回布尔结果
如果不需要等待提交事件触发,调用函数就直接完成所有表单校验、返回结果,可以直接遍历表单执行校验逻辑,不需要绑定提交事件监听器:
function bsvalidate() { 'use strict' const forms = document.querySelectorAll('.needs-validation') let allValid = true Array.from(forms).forEach(form => { if (!form.checkValidity()) { allValid = false } form.classList.add('was-validated') console.log('inside forEach') // 1st console.log console.log('check>>', allValid) }) console.log('outside forEach') // 2nd console.log return allValid }
该方案为同步执行,你需要的打印顺序可以得到保证,调用函数后直接返回所有表单是否全部校验通过的布尔值。
场景2:表单提交触发校验时再返回结果
如果确实需要在表单提交时才触发校验、拿结果,可以用Promise封装逻辑,等待提交事件触发后再返回校验结果:
function bsvalidate() { 'use strict' const forms = document.querySelectorAll('.needs-validation') // 返回Promise实例,提交事件触发后返回校验结果 return new Promise(resolve => { let check = true Array.from(forms).forEach(form => { form.addEventListener('submit', function (event) { if (!form.checkValidity()) { event.preventDefault() event.stopPropagation() check = false } form.classList.add('was-validated') console.log('inside forEach') // 1st console.log console.log('check>>', check) resolve(check) }, false) }) }) } // 调用方式1:then回调处理结果 bsvalidate().then(isValid => { console.log('outside forEach') // 2nd console.log // 后续业务逻辑写在这里 console.log('校验结果:', isValid) }) // 调用方式2:async/await语法(需要在async函数内使用) // const isValid = await bsvalidate() // console.log('outside forEach') // 2nd console.log // console.log('校验结果:', isValid)
注意事项
- 不要用全局变量
window.check存储校验状态,容易被其他逻辑篡改,使用函数内部变量更安全。 - 现在可以直接用
Array.from把NodeList转为数组,不需要使用Array.prototype.slice.call的旧兼容写法。
内容的提问来源于stack exchange,提问作者damdafayton
相关产品推荐
相关产品推荐

