Jquery POST дважды

Пожалуйста, может кто-нибудь просветить меня, почему это дважды отправляет запрос POST? NB: Перед отправкой второго запроса (те же самые данные) существует задержка примерно в 2 минуты.

Код использует GetUserMedia() для отображения веб-канала пользователя и немедленно копирует снимок на холст. Затем он получает URL-адрес данных, прежде чем использовать jquery для отправки его на сервер. Проблема, с которой я сталкиваюсь, заключается в том, что второй почтовый запрос выполняется с теми же данными примерно через две минуты после первого. Я не могу, на всю жизнь, выяснить причину проблемы - пожалуйста, помогите!

// The width and height of the captured photo. We will set the
// width to the value defined here, but the height will be
// calculated based on the aspect ratio of the input stream.
var width = 320;    // We will scale the photo width to this
var height = 0;     // This will be computed based on the input stream
// |streaming| indicates whether or not we're currently streaming
// video from the camera. Obviously, we start at false.
var streaming = false;
// The various HTML elements we need to configure or control. These
// will be set by the startup() function.
var video = null;
var canvas = null;
var track = null;
var video = document.getElementById('video');
var canvas = document.getElementById('canvas');
var photo = document.getElementById('photo');
var kill = null;
// get feed
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
  .then(function (stream) {
    video.srcObject = stream;
    track = stream.getTracks()[0];  // if only one media track
    video.play();
  })
  .catch(function (err) {
    console.info("An error occurred: " + err);
  });

video.addEventListener('canplay', function (ev) {    // when recieving stream

  if (kill === null) {

    if (!streaming) {
      height = video.videoHeight / (video.videoWidth / width);
      if (isNaN(height)) {    // // Firefox currently has a bug
        height = width / (4 / 3);
      }
      video.setAttribute('width', width);    // make sure video and canvas html is correct size
      video.setAttribute('height', height);
      canvas.setAttribute('width', width);
      canvas.setAttribute('height', height);
      streaming = true;
      ev.preventDefault();
      var context = canvas.getContext('2d');
      if (width && height) {
        canvas.width = width;
        canvas.height = height;
        context.drawImage(video, 0, 0, width, height);
        //  !!!!!!!!!!!!!!!!!!!
        $.post('/recv', {
          img: canvas.toDataURL()
        });
        track.stop();
        kill = 1;
        ev.target.removeEventListener(ev.type, arguments.callee);
        return false;
        //  !!!!!!!!!!!!!!!!!!!
      }
    } else {
      return;
    }
  }
}, false);
<!DOCTYPE html>
<html>

<head>
    <title>webrtc snapper</title>
    <script src = "https://code.jquery.com/jquery-3.4.1.min.js"
        integrity = "sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo = " crossorigin = "anonymous"></script>
</head>

<body>
    <div class = "camera">
        <video id = "video"></video>
    </div>
    <canvas id = "canvas">
    </canvas>
    <div class = "output">
        <img id = "photo">
    </div>
    <script src = "capture.js">
    </script>
</body>

</html>

Возможно, вам нужно добавить Promise к своим функциям, поскольку вы настраиваете свой слушатель, прежде чем закончить выполнение функции getUserMedia(). Поэтому ваша функция слушателя запускается снова и снова после завершения выполнения getUserMedia().

Ange Loron 31.05.2019 22:11

Спасибо за ваш комментарий. Пожалуйста, не могли бы вы указать предлагаемые изменения, поскольку я не совсем уверен, что вы имеете в виду. вызов API GUM завершается до того, как прослушиватель событий будет добавлен в «видео» ... Я новичок в js, я, вероятно, сделал что-то нелепое.

harry young 31.05.2019 22:58

Поместите прослушиватель событий в then из getUserMedia.

Ange Loron 01.06.2019 18:13

Никакой разницы...

harry young 03.06.2019 16:06

Это просто закомментированная область, которая вызывается дважды, или это больше похоже на то, что весь addEventListener запускается дважды?

Arthur Hylton 03.06.2019 17:53

Я не совсем уверен. К вашему сведению, я клонировал код с github, связанный с эта страница, так что он должен быть довольно хорошим. Оказывается, даже когда я возвращаюсь к исходному коду с единственным изменением, заключающимся в добавлении сообщения jquery, оно все равно отправляется дважды.

harry young 03.06.2019 18:05

Что произойдет, если вы используете событие loadedmetadata вместо canplay?

Ugo T. 03.06.2019 20:10

проблема в .POST... Неважно, что отправлено, оно всегда дублируется:/

harry young 03.06.2019 20:25

Логически это может произойти только в том случае, если canplay имеет дублирующую привязку, она запускается снова (до отмены привязки) или если снова вызывается вся страница. Показанный код не показывает ни одну из этих ситуаций, поэтому, скорее всего, он находится где-то еще в кодовой базе. Используя инструменты разработчика Chrome, проверьте элемент video, перейдите на вкладку «Прослушиватели событий» и посмотрите, что связано с canplay.

OXiGEN 04.06.2019 19:05

На данный момент это вся кодовая база, кроме простой серверной части expressjs для получения того, что xhr'd в / recv ... Я проверил инструменты chrome dev, и на вкладке прослушивателей событий ничего не отображается. Одна вещь, которая может быть полезной, заключается в том, что сразу после второго запроса к «/recv» на консоли Chrome отображается сообщение об ошибке, которое гласит: «jquery-3.4.1.min.js:2 POST локальный хост: 3000/прием net:: ОШИБКА_EMPTY_RESPONSE"

harry young 04.06.2019 19:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
10
426
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Событие canplay сложное, оно может воспроизводиться более одного раза, например, при изменении текущего времени браузеру нужно загрузить больше данных либо из кеша, либо из сети. Это может вызвать событие canplay.

Для ее решения есть два пути.

Один - как сказано в ответе выше, использовать флаг. Я не поддерживаю это, так как смешивание с флагами может усложнить ваш код, сделать его трудным для чтения и обслуживания.

Второй - отписаться от события:

video.bind('canplay', function (ev) {
   // your logic ....
   video.unbind('canplay')
}

Начиная с jquery 3.0 и далее:

 video.on('canplay', function (ev) {
       // your logic ....
       video.off('canplay')
    }

Приведенный выше код чище, его легче читать и поддерживать.

В конце концов, вам решать, что лучше всего соответствует вашим потребностям.

Спасибо за ваш ответ: до того, как я написал здесь, я сделал тот же вывод, поэтому приятно видеть, что мы на одной странице. Я реализовал предложение с флагом, потому что это казалось самым быстрым вариантом для кого-то вроде меня с такими ограниченными знаниями JS. Пожалуйста, посмотрите на переменную kill - я неправильно ее реализовал? Спасибо :)

harry young 04.06.2019 17:45

Хорошо, я добавил "video.removeEventListener('canplay', function(){return});" в строке, следующей за .POST, и я все еще испытываю ту же проблему с дублированием. ('off' и 'unbind' не могут быть применены - я думаю, это потому, что видео не было выбрано с помощью jquery... Я полагаю, что removeeventlistener выполняет ту же работу?...)

harry young 04.06.2019 18:37

Да, в дело пойдет, попробуй :)

Barr J 05.06.2019 06:14

В приведенном выше коде он уже есть как ev.target.removeEventListener(ev.type, arguments.callee); Проблема была на моем сервере. Тем не менее, спасибо за вашу публикацию.

harry young 05.06.2019 16:30
Ответ принят как подходящий

Я решил проблему, заставив сервер ответить 200 OK,

после получения POST. Кажется, я забыл добавить это, и это вызывало репост JQUERY (или что-то подобное, потому что секция post в экспрессе вызывалась дважды).

Спасибо за ваши ответы.

Другие вопросы по теме