记一次错:循环中调用 Promise 的 resolve 的问题
起因
最近在看方方的《造轮子》,我是直接上 vue-cli 3 的,所以在配置上真的下了很大功夫。今天就出现了在循环里调用 resolve 函数的问题。
先说说我的配置吧,我是使用 vue-cli 3 + vue-cli-plugin-unit-karma 插件来配置的 Karma 的。
vue.config.js
vue-cli 3 是不需要 webpack.config.js 的,所以要将配置 Karam 要使用 vue-cli-plugin-unit-karma 插件,这也是官方推荐的方法,而且这个插件是和 vue-cli-service 配合的连 package.json 里的 test 都不用改,直接 vue-cli-service test:unit
一波带走。这里面我还使用了全局 Sass 文件。
const karmaConfig = require('./karma.config')
module.exports = {
publicPath: process.env.NODE_ENV === 'production'
? '/overwatch-ui/'
: '/',
css: {
loaderOptions: {
sass: {
// @ -> /src
data: `
@import "@/assets/styles/global.scss";
@import "@/assets/styles/reset.scss";
`
}
}
},
pluginOptions: {
karma: {
expressServer: undefined,
karmaConfig: karmaConfig
}
}
}
karam.config.js
注意,这不是官方所用的那种 karam.config.js 文件,我的文件只是返回一个对象,不想在 vue.config.js 里写太长了而已。
module.exports = {
basePath: '',
frameworks: ['mocha', 'chai', 'sinon-chai'],
client: {
chai: {
includeStack: true
},
},
files: [
'tests/**/*.spec.js',
'tests/**/*.spec.ts',
],
reporters: ['progress'],
port: 9876,
colors: true,
autoWatch: true,
browsers: ['ChromeHeadless'],
concurrency: Infinity,
}
Input.spec.js
先定义一下 testProperty
函数,因为我理想的情况是多种值都要测,所以应该循环一个数组,对数组里每个值都做一次测试(就是这个代码坑了,用回调好好的,自己非得装B用 Promise 来玩)。
function testProperty(values) {
return new Promise((resolve, reject) => {
values.forEach((value) => resolve(value))
})
}
这里我就不写那么多代码啦,大家看到这就意会一下就行了。
describe('events', ()=> {
it('can be handled', () => {
const events = ['click', 'change', 'input']
const eventHandler = sinon.stub()
testProperty(events)
.then((eventName) => {
console.log(eventName)
const InputVue = shallowMount(Input, {
listeners: {
[`${eventName}`]: eventHandler
}
})
InputVue.find('input').trigger(eventName)
expect(eventHandler.called).to.equal(true)
})
})
})
说完上面的基本配置,就说说今天的采坑记吧。
没有 Log?
当我运行 yarn run test
的时候,发现 Karma 跑通了,Yes,第一波 Vue + Karam 配置成功!

哎不对,我的 console.log(eventName)
怎么没了?第一反应是 Karam 没有配置好,因为测试是归 Karma 管的。然后 Google 了一下,找到了 Karam runner 里 Karam-Mocha 里的 Issue

然后马上去将 browserConsoleLogOptions
和 captureConsole
里的东西加在 karam.config.js
里。再次运行,Boom,还是不行,什么都没有打印。
config 是谁,它在哪?
虽然这个人很多赞,但是毕竟是个人说辞,不太可靠,他既然说到了 Karma 的配置,那么官方文档肯定会有说呀。Go,下一步 Karam 官方文档。果然我找到一个配置:

说是在 karam.config.js 里设置 config.LOG_INFO
的,像这样:
module.exports = function(config) {
config.set({
logLevel: config.LOG_INFO,
});
};
但是,这种是不是 vue cli 3 的写法,这是 vue cli + webpack.config.js 的写法呀。我了个去,这么写 config 都不知道从哪来,常量 LOG_INFO
肯定是 undefined
。
哎,虽然我不能配置 logLevel: config.LOG_INFO
,但是我可以用命令行呀,所以马上去 package.json 里改脚本命令:
"test": "vue-cli-service test:unit --log-level debug"
开 iTerm2,秒写命令:
yarn run test
但是还是没 log,当时心态已经到崩溃的边缘了。
484你这个 0.5 版本的插件不行啊
现在头号嫌疑犯就是这个插件了,因为 --log-level debug
写在 vue-cli-service
后面,应该是要 vue-cli-service
结合使用的,而这个插件号称自己和 vue-cli-service 完美结合,一看版本才 0.5 想:是不是你这个弱智没写好插件就到处装B了。又去看了这个插件的 Issue。

嗯。。。还很干净。没法了,现在只有两条路
- 写 Issue 给这个插件作者,可能要等一会才能解决,而且不一定能解决。
- 使用降级 vue-cli,使用 vue-cli 和 webpack.config.js 结合的老方法,一定能行,但是麻烦。
两个方法都很难受,所以我选择了第三种方法:在别的地方打 log,是不是真的别的地方都不能打 log 了。所以我在 testProperty
里加了句:
function testProperty(values) {
return new Promise((resolve, reject) => {
console.log(values)
values.forEach((value) => resolve(value))
})
}
结果竟然有 log 了!看来上面的方法全部作废了,别的地方能 log 说明配置完全正确。
循环 resolve 害死人啊
其实我一开始写的 testProperty
是这样的:
function testProperty(values, callback) {
values.forEach(callback)
}
我想了想,是不是有点 low 啊,这样封装好像都没什么意义,所以使用了 Promise 写法。而这种写法只能在循环里调用 resolve(value)
才能将数组元素传入回调里。后面自己再试了试,then()
完了之后只会调用一次 resolve(value)
,而不会在循环里多次调用,我的这种写法纯粹属性猜测去写,所以导致看了半天的 Issue 和 StackOverflow 才慢慢解决了这个问题。
总结
其实我的循环调用 resolve 是可以打出一个 log 的,因为会调用一次,但是前期确实没有将 karam.config.js 里的 client
和 browserConsoleLogOptions
配置好,所以没有 log。
即使加了这个配置选项,可能当时代码本来也点问题,所以一直没发现这种”猜测写法“带来的问题。最后解决的时候确实能回想当初写这样代码的想法:“能不能循环 resolve 呢?嗯试试吧”。
总之,这是一次不错的调错经历,调完真的是身心俱疲。