您如何将 setTimeout 包装在承诺中 [英] How do you wrap setTimeout in a promise

查看:25
本文介绍了您如何将 setTimeout 包装在承诺中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

我创建了一个函数

function promiseTimeout(时间){返回新的承诺(功能(解决,拒绝){setTimeout(function(){resolve(time);},time);});};

尝试将 setTimeout 包装在 Promise 中.

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

 it('使用浏览器后退按钮时应该恢复状态',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){期望(xu.params[0]).to.equal(6);历史.back();}).then(promiseTimeout(10)).then(function(){期望(xu.params[0]).to.equal(4);完毕();});});

我可以在第一个 xh.fire 调用上设置断点,在 xu.fire 调用上设置第二个断点,并且在继续调用时预计会有两秒的间隔从第一个断点到第二个断点.

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

我做错了什么?

解决方案

TL;DR - 您已将 setTimeout 正确包装在 promise 中,问题是您使用不当

.then(promiseTimeout(2000)).then

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

<块引用>

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

promise.then(onFulfilled, onRejected)

onFulfilled 和 onRejected 都是可选参数:

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

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

你没有向 then 传递函数

考虑你的工作方式:

Promise.resolve('hello').then(promiseTimeout(2000)).then(console.log.bind(控制台))

vs 应该如何做:

Promise.resolve('hello').then(function() {返回 promiseTimeout(2000)}).then(console.log.bind(console))

第一个立即输出'hello'

2 秒后第二个输出 2000

因此,您应该:

it('使用浏览器后退按钮时应该恢复状态', function(done) {r.domOK().then(function() {xh.fire('akc-route-change', '/user/4/profile/new');}).那么(函数(){返回 promiseTimeout(2000);}).then(函数(t){xu.fire('akc-route-change', '/user/6');}).那么(函数(){返回 promiseTimeout(10);}).then(函数(t){期望(xu.params[0]).to.equal(6);历史.back();}).那么(函数(){返回 promiseTimeout(10);}).那么(函数(){期望(xu.params[0]).to.equal(4);完毕();});});

或者:

it('使用浏览器后退按钮时应该恢复状态', function(done) {r.domOK().then(function() {xh.fire('akc-route-change', '/user/4/profile/new');}).then(promiseTimeout.bind(null, 2000)).then(函数(t){xu.fire('akc-route-change', '/user/6');}).then(promiseTimeout.bind(null, 10)).then(函数(t){期望(xu.params[0]).to.equal(6);历史.back();}).then(promiseTimeout.bind(null, 10)).then(function() {期望(xu.params[0]).to.equal(4);完毕();});});

2019 年 3 月

<块引用>

多年来,事情发生了很大变化 - 箭头符号使这变得更加容易

首先,我会以不同的方式定义 promiseTimeout

const promiseTimeout = time =>() =>new Promise(resolve => setTimeout(resolve, time, time));

上面返回一个函数,可以调用该函数来创建承诺延迟"并解析为时间(延迟长度).考虑到这一点,我不明白为什么这会非常有用,我宁愿:

const promiseTimeout = time =>结果 =>new Promise(resolve => setTimeout(resolve, time, result));

以上将解析为先前承诺的结果(更有用)

但它是一个返回函数的函数,所以其余的原始代码可以保持不变.然而,关于原始代码的事情是不需要值向下传递到 .then 链,所以,甚至更简单

const promiseTimeout = time =>() =>new Promise(resolve => setTimeout(resolve, time));

并且问题的it块中的原始代码现在可以不变

使用

it('使用浏览器后退按钮时应该恢复状态',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(){期望(xu.params[0]).to.equal(6);历史.back();}).then(promiseTimeout(10)).then(function(){期望(xu.params[0]).to.equal(4);完毕();});});

I am trying to run a test suite for an object that returns a promise. I want to chain several actions together with short timeouts between them. I thought that a "then" call which returned a promise would wait for the promise to be fulfilled before firing the next chained then call.

I created a function

function promiseTimeout (time) {
  return new Promise(function(resolve,reject){
    setTimeout(function(){resolve(time);},time);
  });
};

to try and wrap setTimeout in a Promise.

Then in my test suite, I am calling something like this ...

    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();
      });
    });

I can put a breakpoint on the first xh.fire call and a second one on the xu.fire call and would have expected a two second gap when a continues from the first breakpoint to the second.

Instead it reaches the second breakpoint immediately, and the value of t at that point is undefined.

What am I doing wrong?

解决方案

TL;DR - you've wrapped setTimeout in a promise properly, the issue is you are using it improperly

.then(promiseTimeout(2000)).then

will not do what you expect. The "signature" for .then is 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.

source: https://promisesaplus.com/#point-21

You are not passing a function to then

Consider the way you are doing it:

Promise.resolve('hello')
.then(promiseTimeout(2000))
.then(console.log.bind(console))

vs how it should be done:

Promise.resolve('hello').then(function() { 
    return promiseTimeout(2000)
}).then(console.log.bind(console))

The first outputs 'hello' immediately

The second outputs 2000 after 2 seconds

Therefore, you should be doing:

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();
    });
});

Alternatively:

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();
    });
});

EDIT: March 2019

Over the years, things have changed a lot - arrow notation makes this even easier

Firstly, I would define promiseTimeout differently

const promiseTimeout = time => () => new Promise(resolve => setTimeout(resolve, time, time));

The above returns a function that can be called to create a "promise delay" and resolves to the time (length of delay). Thinking about this, I can't see why that would be very useful, rather I'd:

const promiseTimeout = time => result => new Promise(resolve => setTimeout(resolve, time, result));

The above would resolve to the result of the previous promise (far more useful)

But it's a function that returns a function, so the rest of the ORIGINAL code could be left unchanged. The thing about the original code, however, is that no values are needed to be passed down the .then chain, so, even simpler

const promiseTimeout = time => () => new Promise(resolve => setTimeout(resolve, time));

and the original code in the question's it block can now be used unchanged

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();
  });
});

这篇关于您如何将 setTimeout 包装在承诺中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆