异步等待在 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.
我正在使用 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.