异步等待在 forEach 循环中没有像我预期的那样工作

Async-await not working as I expected in forEach loop

我正在使用 WebRTC 尝试将两个用户连接在一起。我调用 createOffer,然后使用 createOffer returns 设置对等连接的本地描述。我不知道为什么会出现以下错误:

注意:我使用 firebase firestore 作为信令服务器

Uncaught (in promise) DOMException: Cannot set local offer when createOffer has not been called.

这是我的代码:

async function preformSignaling() {
  let users = await negDoc.collection("users").get();
  let newPeerConnection;

  users.forEach(async (doc) => {
    if (isNotAlreadyConnected(doc.id)) {
      newPeerConnection = new UserConnection(servers, doc.id);

      if (doc.id != sessionStorage.getItem("userID") && doc.id != "metadata") {

        let connOfferDescription =
          await newPeerConnection.userPeerConnection.createOffer();

        await newPeerConnection.userPeerConnection.setLocalDescription(
          connOfferDescription
        );

        await doc.collection("offer-candidates").doc("offer").set({
          offer: newPeerConnection.userPeerConnection.localDescription,
        });
      }

      peerConnections.push(newPeerConnection);
    }
  });
}

class UserConnection {
  constructor(servers, remoteUserID) {
    this.userPeerConnection = new RTCPeerConnection(servers);
    this.remoteStream = new MediaStream();
    this.remoteUserID = remoteUserID;
  }

  getRemoteUserID() {
    return this.remoteUserID;
  }
}

我在这里有点盲目刺痛,但在 forEach(或 map、filter、reduce 等)中使用 async-await 是一个常见的问题。它本质上只是触发了一堆异步调用。

它不会等到该回调中发生的事情完成后再触发下一个回调。 forEach 的内部需要等待回调,回调必须 return 一个承诺。

因为你有 let newPeerConnection 在循环之外,你可能在任何 createOffer 调用完成之前多次写入该变量。

如果 none 这些同时调用会相互影响,则可以将该变量带入循环。否则,如果您想 运行 一个一个地使用它们,只需使用 for-of 循​​环。这可能看起来像这样:

async function preformSignaling() {
    let users = await negDoc.collection('users').get();
    let newPeerConnection;

    for (let doc of users) {
        if (!isNotAlreadyConnected(doc.id)) continue;

        newPeerConnection = new UserConnection(servers, doc.id);

        if (
            doc.id !== sessionStorage.getItem('userID') &&
            doc.id !== 'metadata'
        ) {
            let connOfferDescription =
                await newPeerConnection.userPeerConnection.createOffer();

            await newPeerConnection.userPeerConnection.setLocalDescription(
                connOfferDescription
            );

            await doc.collection('offer-candidates').doc('offer').set({
                offer: newPeerConnection.userPeerConnection.localDescription,
            });
        }

        peerConnections.push(newPeerConnection);
    }
}

Note a couple of minor changes in there for better practices: !== not !=, and check the inverse of the bool and continue early to avoid the pyramid of doom.