Подтвердить что ты не робот

Почему мой код не работает в Safari или Opera?

В js есть функция, которая отображает сообщения в таблицу (сообщения хранятся в json). В Google Chrome он работает, но Safari, Opera или Microsoft Edge - нет! В коде есть ошибка, связанная с вызовом setTimeout (callback, 5000) (ничто не отправляется на обратный вызов). Таким образом, For (var i = 0; i <respond.length; i ++) не будет работать с respond === undefined.

Но почему это так?

callback(
  [{
      "time": "1500303264",
      "user": "qwe",
      "message": "we",
      "id": 1
    },
    {
      "time": "1500303987",
      "user": "Max",
      "message": "q",
      "id": 2
    }
  ]);

function smile(mess) {
  var smile = ":)";
  var graficSmile = "<img src = './image/Smile.png' alt='Smile' align='middle'>";
  var string_with_replaced_smile = mess.replace(smile, graficSmile);

  var sad = ":("
  var graficSad = "<img src = './image/Sad.png' alt='Smile' align='middle'>";
  var string_with_replaced_smile_and_sad = string_with_replaced_smile.replace(sad, graficSad);

  return string_with_replaced_smile_and_sad;
}

$.getJSON('data/messages.json', callback);
var exists = [];

function callback(respond) {
  var timeNow = Date.now();

  for (var i = 0; i < respond.length; i++) {
    var data = respond[i];

    if (exists.indexOf(data.id) != -1) continue;

    var timeInMessage = data.time * 1000;
    var diff_time = (timeNow - timeInMessage);

    if (diff_time <= 3600000) {
      var rowClone = $('.mess_hide').clone().removeClass('mess_hide');

      var newDate = new Date(timeInMessage);
      var dateArray = [newDate.getHours(), newDate.getMinutes(), newDate.getSeconds()]
      var res = dateArray.map(function(x) {
        return x < 10 ? "0" + x : x;
      }).join(":");

      $('#messages').append(rowClone);
      $('.time', rowClone).html(res);
      $('.name', rowClone).html(data.user);
      $('.message', rowClone).html(smile(data.message));
      $('.scroller').scrollTop($('#messages').height());

      exists.push(data.id);
    }
  }
  setTimeout(function(){callback(respond)}, 5000);
}
.scroller {
  width: 490px;
  height: 255px;
  max-height: 255px;
  overflow-y: auto;
  overflow-x: hidden;
}

table#messages {
  min-height: 260px;
  width: 100%;
  background: #fffecd;
  border: none;
}

table#messages::-webkit-scrollbar {
  width: 1em;
}

table#messages::-webkit-scrollbar-track {
  -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}

table#messages::-webkit-scrollbar-thumb {
  background-color: darkgrey;
  outline: 1px solid slategrey;
}

tr {
  height: 20%;
  display: block;
}

td.time,
td.name {
  width: 70px;
  max-width: 75px;
  text-align: center;
}

td.name {
  font-weight: bold;
}

form#text_submit {
  display: inline-flex;
  align-items: flex-start;
}

input#text {
  width: 370px;
  height: 30px;
  margin-top: 20px;
  background: #fffecd;
  font-family: 'Montserrat';
  font-size: 16px;
  border: none;
  align-self: flex-start;
}

input#submit {
  padding: 0;
  margin-left: 21px;
  margin-top: 21px;
  height: 30px;
  width: 95px;
  background: #635960;
  border: none;
  color: white;
  font-family: 'Montserrat';
  font-size: 16px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="scroller">
  <table id="messages">
    <tr class="mess_hide">
      <td class="time"></td>
      <td class="name"></td>
      <td class="message"></td>
    </tr>
  </table>
</div>
<form method="POST" id="easyForm">
  <input type="text" name="text" id="text">
  <input type="submit" value="Send" id="submit">
</form>
</div>
4b9b3361

Ответ 1

  • Поскольку предполагается, что массив var exists -, но значение массива ([]) присваивается ему только позже, после вызова $.getJSON(...). Итак, когда callback вызывается для первого значения времени [] не устанавливается для exists. Нам просто нужно переместить var exists выше первого вызова callback.
  • Когда callback вызывается таймером, ему ничего не передается. Но таймер должен перечитывать сообщения из файла и отображать их на экране. Поэтому вместо setTimeout(function(){callback(respond)}, 5000); нам нужно setTimeout(function(){$.getJSON('data/messages.json', callback);}, 5000);.

var exists = [];
$.getJSON('data/messages.json', callback);

function callback(respond) {
  var timeNow = Date.now();

  for (var i = 0; i < respond.length; i++) {
    var data = respond[i];

    if (exists.indexOf(data.id) != -1) continue;

    var timeInMessage = data.time * 1000;
    var diff_time = (timeNow - timeInMessage);

    if (diff_time <= 3600000) {
      var rowClone = $('.mess_hide').clone().removeClass('mess_hide');

      var newDate = new Date(timeInMessage);
      var dateArray = [newDate.getHours(), newDate.getMinutes(), newDate.getSeconds()]
      var res = dateArray.map(function(x) {
        return x < 10 ? "0" + x : x;
      }).join(":");

      $('#messages').append(rowClone);
      $('.time', rowClone).html(res);
      $('.name', rowClone).html(data.user);
      $('.message', rowClone).html(smile(data.message));
      $('.scroller').scrollTop($('#messages').height());

      exists.push(data.id);
    }
  }
  setTimeout(function() {
    $.getJSON('data/messages.json', callback);
  }, 5000);
}

Ответ 2

Так как callback требуется передать массив в качестве аргумента, setTimeout должен убедиться, что при вызове callback он передает массив.

Измените

setTimeout(callback, 5000);

to

setTimeout(function(){callback(respond)}, 5000);

который позволяет вызвать обратный вызов с аргументом как тело анонимной функции, которое вызывается setTimeout.

Кроме того, в качестве побочного примечания, если вы использовали respond.forEach() вместо цикла count for, код был бы намного чище:

   respond.forEach(function(data) {

    if (exists.indexOf(data.id) != -1) continue;

    var timeInMessage = data.time * 1000;
    var diff_time = (timeNow - timeInMessage);

    if (diff_time <= 3600000) {
      var rowClone = $('.mess_hide').clone().removeClass('mess_hide');

      var newDate = new Date(timeInMessage);
      var dateArray = [newDate.getHours(), newDate.getMinutes(), newDate.getSeconds()]
      var res = dateArray.map(function(x) {
        return x < 10 ? "0" + x : x;
      }).join(":");

      $('#messages').append(rowClone);
      $('.time', rowClone).html(res);
      $('.name', rowClone).html(data.user);
      $('.message', rowClone).html(smile(data.message));
      $('.scroller').scrollTop($('#messages').height());

      exists.push(data.id);
    }
  });