在Promise链中使用`.setTimeout()`的正确方法是什么?

时间:2018-10-13 00:09:42

标签: angular typescript

在我正在构建的应用程序中,有一个用例,其中我需要引发第一个API调用,等待响应,然后使用响应中的信息引发第二个API调用。像这样:

firstAPI.call(some input)
            .then(firstResponse => {
                return secondAPI.call(firstResponse);
            })
            .then((secondResponse) => {
                //do something
            })
            .catch(error => {
                console.error(error);
            });

这些都很好。但是,当前由于某种原因,第二个API调用不能在第一个API调用之后立即引发,并且必须间隔一定时间才能起作用。然后,我尝试像这样使用.setTimeout()

firstAPI.call(some input)
            .then(firstResponse => {
                //save the response somewhere
            })
            .then(() => {
                // Wait 1.5s before calling the second API
                return this.sleep(1500);
            })
            .then(() => {
                return secondAPI.call(saved first response);
            })
            .then((secondResponse) => {
                //do something
            })
            .catch(error => {
                console.error(error);
            });

private sleep(milliseconds: number): Promise<Object> {
        return new Promise(resolve => {
            setTimeout(resolve, milliseconds)
        });
    }

我在以下情况下测试了此代码段:

1)第一次和第二次呼叫均成功-正常工作并且睡眠了1.5秒;

2)第一次呼叫失败-正常工作,发现了错误;

3)第一次通话成功,但是第二次通话失败-无法正常工作;错误未捕获!单元测试代码如下:

 describe('when first call succeeds but second call fails', () => {
        it('should log errorMsg', fakeAsync(() => {
            let mockFirstResponse: Promise<Object> = Promise.resolve(some mock response);            
            spyOn(firstAPI, 'call').and.returnValue(mockFirstResponse);
            spyOn(secondAPI, 'call').and.returnValue(Promise.reject(new Error('Oops!')));
            spyOn(console, 'error').and.callThrough();

            underTest.submit(); // Call my function
            tick(1500);

            expect(console.error).toHaveBeenCalled();
        }));
    });

单元测试失败,并显示错误:

  

错误:未捕获(承诺):错误:糟糕!           在resolvePromise(webpack:///~/zone.js/dist/zone.js:469:0 <-configuration / karma / karma-entry.js:128867)           在webpack:///~/zone.js/dist/zone.js:528:0 <-configuration / karma / karma-entry.js:128926

.catch块根本没有执行。

我的假设是.setTimeout()以某种方式破坏了这一链条。首选的方法是什么?

1 个答案:

答案 0 :(得分:0)

我很感谢您的代码正在做非常相似的事情,但请稍作改动。

向链中引入新的承诺,除了延迟链中下一个块的执行外,什么都不会做,

firstAPI.call(someinput)
  .then(firstResponse => {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve(firstResponse);
      }, 1500)
    })
  })
  .then(firstResponse => {
    return secondAPI.call(firstResponse);
  })
  .then((secondResponse) => {
    // do something
  })
  .catch(error => {
    console.error(error);
  });

总的来说,需要延迟的原因可能是由于服务器在响应后执行了一些需要一两秒钟才能完成的处理,或者可能是重新编制索引或使用了一些棘手的扑克游戏。