如何在承诺中包装setTimeout

akc*_*c42 20 javascript promise

我正在尝试为返回promise的对象运行测试套件.我希望将几个动作连在一起,并在它们之间进行短暂的超时.我认为返回承诺的"然后"调用将等待承诺在触发下一个链接然后调用之前完成.

我创建了一个函数

function promiseTimeout (time) {
  return new Promise(function(resolve,reject){
    setTimeout(function(){resolve(time);},time);
  });
};
Run Code Online (Sandbox Code Playgroud)

尝试在承诺中包装setTimeout.

然后在我的测试套件中,我正在调用这样的东西......

    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();
      });
    });
Run Code Online (Sandbox Code Playgroud)

我可以在第一个xh.fire呼叫上设置断点,在呼叫时设置第二个xu.fire呼叫,并且当从第一个断点继续到第二个断点时,预期会有两秒的间隙.

相反,它立即到达第二个断点,并且该t点的值未定义.

我究竟做错了什么?

Jar*_*a X 18

TL; DR - 您已正确地将setTimeout包装在一个承诺中,问题是您使用它是不正确的

.then(promiseTimeout(2000)).then
Run Code Online (Sandbox Code Playgroud)

不会做你期望的..then的"签名"是then(functionResolved, functionRejected)

promise的then方法接受两个参数:

promise.then(onFulfilled,onRejected)

onFulfilled和onRejected都是可选参数:

  • 如果onFulfilled不是函数,则必须忽略它.
  • 如果onRejected不是函数,则必须忽略它.

来源:https://promisesaplus.com/#point-21

你没有传递一个函数

考虑一下你这样做的方式:

Promise.resolve('hello')
.then(promiseTimeout(2000))
.then(console.log.bind(console))
Run Code Online (Sandbox Code Playgroud)

vs应如何做:

Promise.resolve('hello').then(function() { 
    return promiseTimeout(2000)
}).then(console.log.bind(console))
Run Code Online (Sandbox Code Playgroud)

第一个输出'你好'立即

第二次输出2000秒后2秒

因此,您应该这样做:

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();
    });
});
Run Code Online (Sandbox Code Playgroud)

或者:

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();
    });
});
Run Code Online (Sandbox Code Playgroud)


小智 6

要使超时根据需要工作,请编写一个需要延迟的函数,然后返回适合传递给的函数then

function timeout(ms) {
  return () => new Promise(resolve => setTimeout(resolve, ms));
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

Promise.resolve() . then(timeout(1000)) . then(() => console.log("got here"););
Run Code Online (Sandbox Code Playgroud)

但是,您很可能希望访问导致超时的Promise的解析值。在这种情况下,请安排由创建的函数timeout()传递值:

function timeout(ms) {
  return value => new Promise(resolve => setTimeout(() => resolve(value), ms));
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

Promise.resolve(42) . then(timeout(1000)) . then(value => console.log(value));
Run Code Online (Sandbox Code Playgroud)


phi*_*gun 6

上面已经回答了这个问题,但我觉得这可以通过以下方式轻松完成:

const setTimeoutPromise = ms => new Promise(resolve => setTimeout(resolve, ms))
Run Code Online (Sandbox Code Playgroud)

setTimeoutProise函数接受等待时间ms并将其传递给setTimeout函数。一旦等待时间结束,就会执行传递给 promise 的 resolve 方法。

可以这样使用:

setTimeoutPromise(3000).then(doSomething)
Run Code Online (Sandbox Code Playgroud)