简体   繁体   English

多个axios在socket.io中获取请求。 通过`socket.emit`同时发送两个事件

[英]Multiple axios get requests in socket.io. Sending two events via `socket.emit` at the same time

I am trying to create multiple axios requests in socket.io. 我试图在socket.io中创建多个axios请求。 If I have simultaneously: 如果同时有:

socket.emit ("Emit1", req1.data); socket.emit ("Emit2", req2.data);

socket.emit("Emit2", req2.data); works. 作品。 socket.emit ("Emit1", req1.data); does not work. 不起作用。

When I remove socket.emit("Emit2", req2.data); 当我删除socket.emit("Emit2", req2.data); --> emit1 works. -> emit1作品。

How to combine it so that it works simultaneously?. 如何组合它以使其同时工作?

Can I create two servers. 我可以创建两个服务器。 One supporting the first component and request get url1 and a second server that supports request url2 ? 一个支持第一个组件和请求的服务器获取url1 ,另一个支持请求url2服务器?

const Emit = async socket => {
    try{
      const [req1, req2] = await Promise.all([
        axios.get(url1, {
          headers: {

          }
        }),
        axios.get(url2, {
          headers: {
            'Authorization': `Bearer ${token}`
          }
        })
      ]);

      socket.emit("Emit1", req1.data);
      socket.emit("Emit2", req2.data); 
    }

    catch(error){
        console.log(error)
    }
};

Client 客户

First component: 第一部分:

import socketIOClient from "socket.io-client";

componentDidMount() {
    axios.get
        axios({
            url,
            method: "GET",
            headers: {
                'Authorization': `Bearer ${token}`
            }
        })
        .then(res => {
            this.setState({
                scores: res.data,
                activeTab: res.data[0].id
            });
        })
        .catch(error => {
            console.log(error);
        })      
}


componentDidUpdate(prevProps, prevState) {
    const endpoint = 'http://127.0.0.1:3000'; 

    if (prevState.scores !== this.state.scores) {
        const socket = socketIOClient(endpoint);
        socket.on("Emit1", data => this.setState({ 
            scores: data 
        }));
    }
}

Second component: 第二部分:

import socketIOClient from "socket.io-client";

componentDidMount() {
    axios.get
        axios({
            url,
            method: "GET",
            headers: {
                'Authorization': `Bearer ${token}`
            }
        })
        .then(res => {
            this.setState({
                abcd: res.data
            });
        })
        .catch(error => {
            console.log(error);
        })      
}


componentDidUpdate(prevProps, prevState) {
    const endpoint = 'http://127.0.0.1:3000'; 

    if (prevState.abcd !== this.state.abcd) {
        const socket = socketIOClient(endpoint);
        socket.on("Emit2", data => this.setState({ 
            abcd: data 
        }));
    }
}

I've been working on your question for a while now and this are my conclusions: 我一直在研究您的问题已有一段时间了,这是我的结论:

Event emission works just fine 事件发射工作正常

I've reconstructed your backend this way: 我以这种方式重建了您的后端:

const express = require('express')
const app = express()
const http = require('http').createServer(app)
const io = require('socket.io')(http)
const port = 3003

app.use(express.json())

app.get('/emit', async({ res }) => {
    const [data1, data2] = await Promise.all([fakeApiCall(1), fakeApiCall(2)])
    io.emit('Emit1',data1)
    io.emit('Emit2',data2)
    res.status(200).json('emitted')
})

const fakeApiCall = id =>{
    return new Promise((resolve, reject) =>{
        setTimeout(() => resolve(`data${id}`), 3000)
    })
}

http.listen(port, () => console.log('listening on port ' + port))

Essencially that's exactly what you are doing, and works just fine, both events are emmited after Promise.all solves all promises. 从本质上讲,这就是您正在做的事情,并且工作正常,这两个事件都在Promise.all兑现所有诺言之后Promise.all

Frontend setup works 前端设置工作

After that I've made a version of your frontend: 之后,我制作了您的前端版本:

App.js: App.js:

import React from 'react'
import ComponentA from './ComponentA'
import ComponentB from './ComponentB'

const App = () => {
    return (
        <>
            <ComponentA />
            <ComponentB />
        </>
    )
}


export default App

Component A : 成分A:

import React from 'react'
import socketIOClient from 'socket.io-client'

class ComponentA extends React.Component {
    state = {
        data: null
    }

    componentDidMount(){
        setTimeout(() => this.setState({data: 'bla'}), 2000)
    }


    componentDidUpdate(prevProps, prevState) {
        const endpoint = 'http://127.0.0.1:3003';

        if (prevState.data !== this.state.data) {
            const socket = socketIOClient(endpoint);
            socket.on("Emit1", data => this.setState({ data }))
        }
    }

    render() {
        const { data } = this.state
        return (
            <div>
                {data}
            </div>
        )
    }
}
export default ComponentA

Component B : 成分B:

import React from 'react'
import socketIOClient from 'socket.io-client'

class ComponentB extends React.Component {
    state = {
        data: null
    }

    componentDidMount(){
        setTimeout(() => this.setState({data: 'bla'}), 2000)
    }


    componentDidUpdate(prevProps, prevState) {
        const endpoint = 'http://127.0.0.1:3003';

        if (prevState.data !== this.state.data) {
            const socket = socketIOClient(endpoint);
            socket.on("Emit2", data => this.setState({ data }))
        }
    }

    render() {
        const { data } = this.state
        return (
            <div>
                {data}
            </div>
        )
    }
}
export default ComponentB

And surprisingly... It works just fine! 令人惊讶的是,它工作得很好! So, what is the difference here? 那么,这里有什么区别? Everything looks the same (how the events are emitted, how the listener is only inserted in componentDidUpdate , how the state changes after an async call in componentDidMount ). 一切看起来都一样(该事件是如何发出的,如何监听器只在插入componentDidUpdate ,如何在一个异步调用后的状态变化componentDidMount )。 So the only thing that can possibly be interfering is the axios call you make inside componentDidMount , cause in both components the io.listen isn't setted at componentDidMount how it should be (I assume you have reasons for that), so both components MUST update the state before the event is emmited, otherwise if the properties data or abcd don't get updated in time the event listener will be called after the backend emits the data. 因此,唯一可能造成干扰的是您在componentDidMount内部进行的axios调用,这是因为两个组件中的io.listen都没有在componentDidMount设置(应该是有原因的),所以两个组件都必须在发出事件之前更新状态,否则,如果未及时更新属性dataabcd则在后端发出数据后将调用事件侦听器。 And your claim about how if you omit Emit2 Emit1 will work just fine. 您关于如何省略Emit2 Emit1也可以正常工作。 But, what about omit Emit1 ? 但是,忽略Emit1呢? Emit2 will work as well? Emit2也可以吗? Looks like a race condition, something in componentA 's componentDidMount is preventing componentB from updating or vice-versa 看起来像是竞争条件, componentAcomponentDidMount某些内容阻止了componentB的更新,反之亦然

Possible Solution 可能的解决方案

Place the io's listeners in componentDidMount in both components to determine if this is the case. 放置在io的听众componentDidMount在这两个组件,以确定是否是这种情况。 Cause honestly, I couldn't think in any other problem that may be causing this. 老实说,我无法想到可能导致此问题的任何其他问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM