You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jest与Sinon.JS中server.requests的Promise特性疑问

为什么Sinon fakeServer的requests不是Promise,但Promise.all能“正常工作”?

这个问题的核心是两个点:Promise.all的灵活处理逻辑,以及你对Sinon fakeServer的requests数组的误解。咱们慢慢说清楚:

1. Promise.all根本不要求元素必须是Promise

Promise.all的设计非常灵活,它接收的数组里的元素可以是任何值——不一定非得是Promise对象。对于每个元素,它会自动用Promise.resolve(item)做一层包装:

  • 如果item本身是Promise,就老老实实等它resolve/reject;
  • 如果item是thenable对象(也就是有.then()方法的普通对象),就会按照thenable的规则处理,等待它的回调执行;
  • 如果都不是,就直接返回一个已resolve的Promise,值就是item本身。

所以哪怕你给Promise.all传一堆字符串、数字,甚至像Sinon的FakeXMLHttpRequest这种普通对象,它也能正常执行——只是不会等待任何异步操作,直接进入then回调。

2. Sinon fakeServer的requests里到底是什么?

你用sinon.fakeServer.create()创建的server,它的requests数组存的是Sinon FakeXMLHttpRequest实例——这是Sinon模拟的XMLHttpRequest对象,用来拦截浏览器的真实请求。它确实不是标准Promise,所以你直接调用server.requests[0].then()会报错,因为它本身没有这个方法。

3. 你觉得“Promise.all(server.requests)能等待所有请求完成”,大概率是测试顺序的巧合

Sinon的fakeServer拦截请求后,并不会自动完成请求——你必须手动调用每个请求实例的.respond()方法,才能模拟请求成功/失败的状态。比如:

// 触发请求
store.dispatch(getDataThunk());
// 手动响应所有被拦截的请求
server.requests.forEach(req => {
  req.respond(200, {'Content-Type': 'application/json'}, JSON.stringify({data: 'test'}));
});
// 这时候再做断言,或者等待action返回的Promise
await store.dispatch(getDataThunk());

那为什么你用Promise.all(server.requests)感觉能正常工作?很大可能是你在测试中,是先手动调用了.respond(),再执行Promise.all的then回调——这时候看起来像是Promise.all在等待请求完成,但实际上请求已经被你手动处理完了,Promise.all只是刚好在这之后执行而已。

正确的做法:等待真实的Promise

如果你想等待请求处理完成,应该等待你的action creator返回的Promise,而不是Sinon的requests数组。比如你之前的代码里:

const requests = [];
let getDataThunk = actions.getData();
requests.push(store.dispatch(getDataThunk)); // 这里dispatch返回的是Promise
await Promise.all(requests); // 这才是真正等待请求完成的正确方式

而对于Sinon的fakeServer,它的作用是拦截请求、模拟响应,你需要在触发请求后,先手动调用.respond(),再等待action的Promise完成。

内容的提问来源于stack exchange,提问作者nonopolarity

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 16:57:43