我正在尝试为返回 promise 的对象运行测试套件。我想将多个操作链接在一起,并在它们之间设置较短的超时时间。我认为返回 promise 的“then”调用将等待 promise 履行,然后再触发下一个链接的 then 调用。
我创建了一个函数
function promiseTimeout (time) {
return new Promise(function(resolve,reject){
setTimeout(function(){resolve(time);},time);
});
};
尝试将 setTimeout 包装在 Promise 中。
然后在我的测试套件中,我调用类似这样的内容......
it('should restore state when browser back button is used',function(done){
r.domOK().then(function(){
xh.fire('akc-route-change','/user/4/profile/new');
}).then(promiseTimeout(2000)).then(function(t){
xu.fire('akc-route-change','/user/6');
}).then(promiseTimeout(10)).then(function(t){
expect(xu.params[0]).to.equal(6);
history.back();
}).then(promiseTimeout(10)).then(function(){
expect(xu.params[0]).to.equal(4);
done();
});
});
我可以在第一个xh.fire
上放置一个断点调用第二个电话 xu.fire
当 a 从第一个断点继续到第二个断点时,预计会出现两秒的间隙。
相反,它立即到达第二个断点,并且 t
的值此时未定义。
我做错了什么?
最佳答案
TL;DR - 您已将 setTimeout 正确包装在 promise 中,问题是您使用不当
.then(promiseTimeout(2000)).then
不会做你期望的事情。 .then 的“签名”是 then(functionResolved, functionRejected)
A promise’s then method accepts two arguments:
promise.then(onFulfilled, onRejected)
Both onFulfilled and onRejected are optional arguments:
- If onFulfilled is not a function, it must be ignored.
- If onRejected is not a function, it must be ignored.
来源:https://promisesaplus.com/#point-21
您没有将函数传递给 then
考虑一下你的做法:
Promise.resolve('hello')
.then(promiseTimeout(2000))
.then(console.log.bind(console))
与应该如何完成:
Promise.resolve('hello').then(function() {
return promiseTimeout(2000)
}).then(console.log.bind(console))
第一个立即输出“hello”
第二个在2秒后输出2000
因此,你应该这样做:
it('should restore state when browser back button is used', function(done) {
r.domOK().then(function() {
xh.fire('akc-route-change', '/user/4/profile/new');
}).then(function() {
return promiseTimeout(2000);
}).then(function(t) {
xu.fire('akc-route-change', '/user/6');
}).then(function() {
return promiseTimeout(10);
}).then(function(t) {
expect(xu.params[0]).to.equal(6);
history.back();
}).then(function() {
return promiseTimeout(10);
}).then(function() {
expect(xu.params[0]).to.equal(4);
done();
});
});
或者:
it('should restore state when browser back button is used', function(done) {
r.domOK().then(function() {
xh.fire('akc-route-change', '/user/4/profile/new');
}).then(promiseTimeout.bind(null, 2000)
).then(function(t) {
xu.fire('akc-route-change', '/user/6');
}).then(promiseTimeout.bind(null, 10)
).then(function(t) {
expect(xu.params[0]).to.equal(6);
history.back();
}).then(promiseTimeout.bind(null, 10)
).then(function() {
expect(xu.params[0]).to.equal(4);
done();
});
});
编辑:2019 年 3 月
Over the years, things have changed a lot - arrow notation makes this even easier
首先,我会以不同的方式定义promiseTimeout
const promiseTimeout = time => () => new Promise(resolve => setTimeout(resolve, time, time));
上面返回一个函数,可以调用该函数来创建“ promise 延迟”并解析为时间(延迟长度)。考虑到这一点,我不明白为什么这会非常有用,而是:
const promiseTimeout = time => result => new Promise(resolve => setTimeout(resolve, time, result));
以上将解析为先前 promise 的结果(更有用)
但它是一个返回函数的函数,因此原始代码的其余部分可以保持不变。然而,原始代码的问题是不需要在 .then 链中传递任何值,因此,甚至更简单
const promiseTimeout = time => () => new Promise(resolve => setTimeout(resolve, time));
问题的 it
block 中的原始代码现在可以使用不变
it('should restore state when browser back button is used',function(done){
r.domOK().then(function(){
xh.fire('akc-route-change','/user/4/profile/new');
}).then(promiseTimeout(2000)).then(function(){
xu.fire('akc-route-change','/user/6');
}).then(promiseTimeout(10)).then(function(){
expect(xu.params[0]).to.equal(6);
history.back();
}).then(promiseTimeout(10)).then(function(){
expect(xu.params[0]).to.equal(4);
done();
});
});
关于javascript - 如何将 setTimeout 包装在 Promise 中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33843091/