2
votes

Récupérez l'appel toutes les 2 secondes, mais ne voulez pas que les demandes s'empilent

J'essaie de passer un appel API et je souhaite qu'il se répète toutes les 2 secondes. Cependant, je crains que si le système ne reçoive pas une demande dans les 2 secondes, il construira des demandes et continuera d'essayer de les envoyer. Comment puis-je éviter cela?

Voici l'action que j'essaie de fetch :

function ping() {
    setInterval(
        getMachineAction(),
        2000
    );        
}

Et puis je l'appelle avec un setInterval .

const getMachineAction = async () => {
    try {
        const response = await fetch( 'https://localhost:55620/api/machine/');
        if (response.status === 200) {
            console.log("Machine successfully found.");
            const myJson = await response.json(); //extract JSON from the http response
            console.log(myJson);               
        } else {
            console.log("not a 200");
        }
    } catch (err) {
        // catches errors both in fetch and response.json
        console.log(err);
    }
};

J'ai pensé à faire une promesse comme une structure dans le setInterval pour m'assurer que la récupération avait fonctionné et terminé, mais n'a pas pu obtenir ça marche.


8 commentaires

Toutes les 2 secondes sont-elles une exigence exacte? Sinon, ne le faites pas toutes les 2 secondes. Utilisez setTimeout et planifiez les 2 secondes suivantes après la fin des précédentes.


Il y aura un temps défini, que ce soit 2 secondes ou 30 secondes dépendra d'une variable, mais il restera cohérent. (donc s'il est réglé sur toutes les 2 secondes, cela doit se produire toutes les 2 secondes)


Peut-être regardez dans étranglement / débouncing - j'oublie lequel est lequel. lodash a les deux méthodes.


Que voulez-vous qu'il advienne de la demande précédente à 2 secondes? Doit-il annuler? Quelle est votre exigence relative au «mauvais cas»?


@ zero298 le "mauvais cas" (c'est-à-dire que cela prend plus de 2 secondes) est que je veux qu'il ignore cette demande, puis en envoie une seule nouvelle. Donc à 0 seconde, la demande est envoyée. Il faut 3 secondes pour s'exécuter, puis 2 secondes plus tard (à 5), il devrait être réexécuté. Donc, cela prolonge simplement le temps jusqu'à ce qu'il envoie.


@Andy Ni l'un ni l'autre n'aidera ici


@Bergi, je suis d'accord. Avez-vous des recommandations? J'ai tendance à penser que la réponse de charlietfl est la voie à suivre.


L'approche de @thalacker takrishna est la voie à suivre. Voir également ici


3 Réponses :


0
votes

Simple! Stockez simplement s'il fait actuellement une requête et stockez si le minuteur s'est déclenché sans envoyer de nouvelle requête.

setInterval(getMachineAction, 2000); 

Pour démarrer l'intervalle, vous devez omettre le () code>:

let in_progress = false;
let missed_request = false;
const getMachineAction = async () => {
    if (in_progress) {
        missed_request = true;
        return;
    }
    in_progress = true;
    try {
        const response = await fetch('https://localhost:55620/api/machine/');
        if (missed_request) {
            missed_request = false;
            setTimeout(getMachineAction, 0);
        }
        if (response.status === 200) {
            console.log("Machine successfully found.");
            const myJson = await response.json(); //extract JSON from the http response
            console.log(myJson);               
        } else {
            console.log("not a 200");
        }
    } catch (err) {
        // catches errors both in fetch and response.json
        console.log(err);
    } finally {
        in_progress = false;
    }
};


2 commentaires

Salut @ wizzwizz4, cela fonctionnerait probablement si j'étais d'accord pour ignorer les demandes (c'est-à-dire exécuter à 2,4,8,10 et qu'il en avait ignoré 6), mais je veux que cela fonctionne comme s'il s'exécutait dès que possible, puis 2 secondes après que (c'est-à-dire exécuter à 2,4,7,9,10 où le 6 a pris une seconde supplémentaire donc maintenant ses 2 secondes après). De plus, je pense que vous devez définir votre variable in_progress sur true dans la première ligne après try , n'est-ce pas? Merci d'avoir pris le temps de répondre!


@thalacker Oui, je le fais. (Ou la première ligne avant, ce qui fonctionne.) Et cela devrait faire 2, 4, 6,3, 8, 10 si celui qui commence sur 4 prend 2,3 secondes, contrairement à la solution de charlietfi. La solution Promise.all est soignée, mais semble fonctionner presque de la même manière que la solution de chatlietfi (2, 4, 6.3, 8.3, 10.3). Quelle fonctionnalité recherchiez-vous?



3
votes

Vous pouvez ajouter un enfin à votre try / catch avec un setTimeout au lieu d'utiliser votre setInterval .

Notez qu'une longue interrogation comme celle-ci crée beaucoup plus de charge sur le serveur que l'utilisation de websockets qui sont eux-mêmes beaucoup plus en temps réel

const getMachineAction = async () => {
    try {
        const response = await fetch( 'https://localhost:55620/api/machine/');
        if (response.status === 200) {
            console.log("Machine successfully found.");
            const myJson = await response.json(); //extract JSON from the http response
            console.log(myJson);               
        } else {
            console.log("not a 200");
        }
    } catch (err) {
        // catches errors both in fetch and response.json
        console.log(err);
    } finally {
        // do it again in 2 seconds
        setTimeout(getMachineAction , 2000);
    }
};

getMachineAction()


4 commentaires

Notez que cela se produit 2000 secondes après la fin de la requête, et non 2000 secondes après le démarrage de la requête.


@charlietfl avez-vous une ressource Websockets que vous recommanderiez de consulter ou de lire?


Quelle langue utilisez-vous dans le back-end? Effectuez simplement une recherche sur les Websockets . S'il s'agit d'un serveur de nœuds, consultez socket.io


@charlietfl J'exécute une API Web C # .NET Core. Je peux rechercher des sockets Web C #. Se connecter principalement via des appareils externes pour collecter des données



5
votes

La solution Promise.all ()

Cette solution garantit que vous ne manquez pas l'exigence de délai de 2 secondes ET que vous ne déclenchez pas non plus un appel lorsqu'un autre appel réseau est en cours.

function callme(){
//This promise will resolve when the network call succeeds
//Feel free to make a REST fetch using promises and assign it to networkPromise
var networkPromise = fetch('https://jsonplaceholder.typicode.com/todos/1');


//This promise will resolve when 2 seconds have passed
var timeOutPromise = new Promise(function(resolve, reject) {
  // 2 Second delay
  setTimeout(resolve, 2000, 'Timeout Done');
});

Promise.all(
[networkPromise, timeOutPromise]).then(function(values) {
  console.log("Atleast 2 secs + TTL (Network/server)");
  //Repeat
  callme();
});
}
callme();

Remarque: Cela prend en charge la définition de la mauvaise casse comme demandé par l'auteur de la question:

"le" mauvais cas "(c'est-à-dire que cela prend plus de 2 secondes ) est que je veux qu'il ignore cette demande, puis en envoie une nouvelle. Donc, à 0 seconde, la demande est envoyée. Cela prend 3 secondes pour s'exécuter, puis 2 secondes plus tard (à 5), il devrait réexécuter. Donc, il étend simplement le jusqu'à ce qu'il envoie. "


3 commentaires

On dirait que cela fonctionnerait très bien. La fonction callme () ou la networkPromise serait-elle mon getMachineAction ?


networkPromise sera getMachineAction - callme n'est qu'un wrapper !! Bonne chance avec votre codage


Je vois ça maintenant. Ugh, erreur stupide. Merci!