首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Javascript等待在异步函数中不受尊重

Javascript等待在异步函数中不受尊重
EN

Stack Overflow用户
提问于 2019-06-28 13:36:06
回答 1查看 535关注 0票数 0

我很难弄清楚为什么我的等待语句没有得到尊重,代码在完成异步函数之前就开始了。

我的代码:

代码语言:javascript
复制
  async getSensors(boardId: number): Promise<Sensor[]> {
    console.log('call sensor');
    const sensors: Sensor[] = [];
    await this.http.get<object[]>(API_URL + 'sensors/' + boardId).toPromise().then(res => {
      console.log('http sensor');
      res.forEach(r => sensors.push(GenericDeserialize(r, Sensor)));
    });
    console.log('return sensor');
    return sensors;
  }

  async getRelays(boardId: number): Promise<Relay[]> {
    console.log('call relay');
    const relays: Relay[] = [];
    await this.http.get<object[]>(API_URL + 'relays/' + boardId).toPromise().then(res => {
      console.log('http relay');
      res.forEach(r => relays.push(GenericDeserialize(r, Relay)));
    });
    console.log('return relay');
    return relays;
  }

  async getBoards(): Promise<Board[]> {
    const boards: Board[] = [];
    await this.http.get<object[]>(API_URL + 'boards').toPromise().then(async res => {
      console.log('http boards');
      await res.forEach(async b => {
        console.log('loop', b);
        const board = GenericDeserialize(b, Board);
        await this.getSensors(board.boardId).then(sensors => board.sensors = sensors);
        await this.getRelays(board.boardId).then(relays => board.relays = relays);
        boards.push(board);
      });
    });
    console.log('return boards');
    return boards;
  }

我的茉莉花测试:

代码语言:javascript
复制
  it('should have two sensors and one relay', async () => {
    const service: DataService = TestBed.get(DataService);
    const boards = await service.getBoards();
    const board = boards[0];
    expect(board.sensors.length).toBe(2);
    expect(board.relays.length).toBe(1);

  });

这是控制台在运行测试时输出的实际“调用堆栈”:

代码语言:javascript
复制
'return relay'
'http relay'
'return relay'
'http boards'
'loop', Object{board_id: 0, board_name: 'test'}
'call sensor'
'loop', Object{board_id: 1234, board_name: 'esp1'}
'call sensor'
'return boards'

这就是我所期待的“呼叫堆栈”:

代码语言:javascript
复制
'http boards'
'loop', Object{board_id: 0, board_name: 'test'}
'call sensor'
'http sensor'
'return sensor'
'call relay'
'http relay'
'return relay'
'loop', Object{board_id: 1234, board_name: 'esp1'}
'call sensor'
'http sensor'
'return sensor'
'call relay'
'http relay'
'return relay'
'return boards'
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-28 13:41:28

你的问题是:

代码语言:javascript
复制
await res.forEach(async b => {
  console.log('loop', b);
  const board = GenericDeserialize(b, Board);
  await this.getSensors(board.boardId).then(sensors => board.sensors = sensors);
  await this.getRelays(board.boardId).then(relays => board.relays = relays);
  boards.push(board);
});

forEach总是返回undefined,而await undefined只等待一个微滴答;而forEach完全忽略了回调的返回值,因此回调创建的承诺永远不会用于任何事情,也不会等待它们。

如果要在并行中处理这些数据,只需将其改为map并添加Promise.all即可。

代码语言:javascript
复制
await Promise.all(res.map(async b => {
  console.log('loop', b);
  const board = GenericDeserialize(b, Board);
  await this.getSensors(board.boardId).then(sensors => board.sensors = sensors);
  await this.getRelays(board.boardId).then(relays => board.relays = relays);
  boards.push(board);
}));

如果要在系列中执行这些操作,请使用循环:

代码语言:javascript
复制
for (const b of res) {
  console.log('loop', b);
  const board = GenericDeserialize(b, Board);
  await this.getSensors(board.boardId).then(sensors => board.sensors = sensors);
  await this.getRelays(board.boardId).then(relays => board.relays = relays);
  boards.push(board);
}

附带注意:你做了很多this.http.get<object[]>(API_URL + /*...*/).toPromise()。我倾向于用一种实用的方法:

代码语言:javascript
复制
callAPI(call: string): Promise<object[]> {
    return this.http.get<object[]>(API_URL + call).toPromise();
}

这也使得这样的改变是合理的:

代码语言:javascript
复制
await this.http.get<object[]>(API_URL + 'relays/' + boardId).toPromise().then(res => {
  console.log('http relay');
  res.forEach(r => relays.push(GenericDeserialize(r, Relay)));
});

代码语言:javascript
复制
relays.push(...(await this.callAPI('relays/' + boardId)).map(r => GenericDeserialize(r, Relay)));

或者如果你真的想要那个console.log

代码语言:javascript
复制
relays.push(...(await this.callAPI('relays/' + boardId)).map(r => {
  console.log('http relay');
    return GenericDeserialize(r, Relay);
}));
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56807968

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档