Максимальный размер стека вызовов превышен

Я использую файл библиотеки JavaScript Direct Web Remoting (DWR) и получаю сообщение об ошибке только в Safari (на рабочем столе и в iPad)

В нем говорится

Максимальный размер стека вызовов.

Что именно означает эта ошибка и она полностью прекращает обработку?

Также любое исправление для браузера Safari (Фактически на iPad Safari, он говорит

JS: выполнение превысило время ожидания

который я предполагаю, является той же проблемой стека вызовов)

Ответ 1

Это означает, что где-то в вашем коде вы вызываете функцию, которая в свою очередь вызывает другую функцию и т.д., пока вы не достигнете предела стека вызовов.

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

Просмотр стека

Рассмотрим этот код...

(function a() {
    a();
})();

Вот стопка после нескольких вызовов...

Web Inspector

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

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

(function a(x) {
    // The following condition 
    // is the base case.
    if ( ! x) {
        return;
    }
    a(--x);
})(10);

Ответ 2

Иногда вы можете получить это, если вы случайно импортируете/внедрите один и тот же файл JavaScript дважды, стоит проверить это на вкладке ресурсов инспектора.

Ответ 3

В моем случае я отправлял элементы ввода вместо их значений:

$.post( '',{ registerName: $('#registerName') } )

Вместо:

$.post( '',{ registerName: $('#registerName').val() } )

Это заморозило мою вкладку Chrome до такой степени, что даже не отображало диалоговое окно "Ждать/убивать", когда страница перестала отвечать на запросы...

Ответ 4

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

В других браузерах есть либо большие стеки (поэтому вместо этого вы получаете тайм-аут), либо по какой-то причине они проглатывают ошибку (возможно, плохо поставленный try-catch).

Используйте отладчик для проверки стека вызовов при возникновении ошибки.

Ответ 5

В моем случае я преобразовал большой массив байтов в строку, используя следующее:

String.fromCharCode.apply(null, new Uint16Array(bytes))

bytes содержало несколько миллионов записей, которые слишком велики для размещения в стеке.

Ответ 6

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

Я нашел некоторые из новых инструментов отладки Chrome полезными для этого.

Перейдите на Performance tab, убедитесь, что Javascript samples включены, и вы получите что-то вроде этого.

Это довольно очевидно, где переполнение здесь! Если вы нажмете на extendObject вы сможете увидеть точный номер строки в коде.

enter image description here

Вы также можете увидеть время, которое может или не может быть полезным, или красная сельдь.

enter image description here


Еще один полезный трюк, если вы не можете найти проблему, - это поместить множество операторов console.log там, где вы думаете, что проблема. Предыдущий шаг выше может помочь вам в этом.

В Chrome, если вы неоднократно выводите идентичные данные, он будет отображаться так, как показано, где проблема более ясна. В этом случае стек достиг 7152 фреймов, прежде чем окончательно рухнул:

enter image description here

Ответ 7

В моем случае событие click распространялось на дочерний элемент. Итак, мне пришлось поставить следующее:

e.stopPropagation()

по событию клика:

 $(document).on("click", ".remove-discount-button", function (e) {
           e.stopPropagation();
           //some code
        });
 $(document).on("click", ".current-code", function () {
     $('.remove-discount-button').trigger("click");
 });

Вот HTML-код:

 <div class="current-code">                                      
      <input type="submit" name="removediscountcouponcode" value="
title="Remove" class="remove-discount-button">
   </div>

Ответ 8

Проверьте сведения об ошибках на консоли панели инструментов Chrome dev, это даст вам функции в стеке вызовов и направит вас к рекурсии, вызывающей ошибку.

Ответ 10

В моем случае два модажа jQuery отображались друг на друга. Предотвращение этой проблемы.

Ответ 11

Почти каждый ответ здесь утверждает, что это может быть вызвано только бесконечным циклом. Это неправда, в противном случае вы могли бы перегрузить стек через глубоко вложенные вызовы (не говоря уже о том, что это эффективно, но это, безусловно, возможно). Если у вас есть контроль над вашей виртуальной машиной JavaScript, вы можете настроить размер стека. Например:

node --stack-size=2000

Смотрите также: Как я могу увеличить максимальный размер стека вызовов в Node.js

Ответ 12

Недавно мы добавили поле на сайт администратора, над которым мы работаем - contact_type... easy right? Что ж, если вы вызываете select "type" и пытаетесь отправить его через вызов jquery ajax, это завершится неудачно с этой ошибкой, скрытой глубоко в jquery.js. Не делайте этого:

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, type:type }
});

Проблема в том, что type: type - я считаю, что мы называем аргумент "type" - наличие значения переменной с именем type не является проблемой. Мы изменили это на:

$.ajax({
    dataType: "json",
    type: "POST",
    url: "/some_function.php",
    data: { contact_uid:contact_uid, contact_type:type }
});

И переписал some_function.php соответственно - проблема решена.

Ответ 13

Оба вызова идентичного кода ниже, если оно уменьшено на 1, работают в Chrome 32 на моем компьютере, например. 17905 по сравнению с 17904. Если они выполняются так, они выдают ошибку "RangeError: Максимальный размер стека вызовов". Похоже, что это ограничение не является жестким, а зависит от оборудования вашего аппарата. Похоже, что если вызывается как функция, этот самоналоженный предел выше, чем если он вызывается как метод, то есть этот конкретный код использует меньше памяти при вызове как функцию.

Вызывается как метод:

var ninja = {
    chirp: function(n) {
        return n > 1 ? ninja.chirp(n-1) + "-chirp" : "chirp";
    }
};

ninja.chirp(17905);

Вызывается как функция:

function chirp(n) {
    return n > 1 ? chirp( n - 1 ) + "-chirp" : "chirp";
}

chirp(20889);

Ответ 14

вы можете найти свою рекурсивную функцию в браузере crome, нажмите ctrl + shift + j, а затем вкладку source, которая дает вам поток компиляции кода, и вы можете найти, используя точку останова в коде.

Ответ 15

Я также столкнулся с подобной проблемой, вот подробности  при загрузке логотипа с помощью выпадающего меню для загрузки логотипа

<div>
      <div class="uploader greyLogoBox" id="uploader" flex="64" onclick="$('#filePhoto').click()">
        <img id="imageBox" src="{{ $ctrl.companyLogoUrl }}" alt=""/>
        <input type="file" name="userprofile_picture"  id="filePhoto" ngf-select="$ctrl.createUploadLogoRequest()"/>
        <md-icon ng-if="!$ctrl.isLogoPresent" class="upload-icon" md-font-set="material-icons">cloud_upload</md-icon>
        <div ng-if="!$ctrl.isLogoPresent" class="text">Drag and drop a file here, or click to upload</div>
      </div>
      <script type="text/javascript">
          var imageLoader = document.getElementById('filePhoto');
          imageLoader.addEventListener('change', handleImage, false);

          function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {

                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }
      </script>
      </div>

CSS.css

.uploader {
  position:relative;
  overflow:hidden;
  height:100px;
  max-width: 75%;
  margin: auto;
  text-align: center;

  img{
    max-width: 464px;
    max-height: 100px;
    z-index:1;
    border:none;
  }

  .drag-drop-zone {
    background: rgba(0, 0, 0, 0.04);
    border: 1px solid rgba(0, 0, 0, 0.12);
    padding: 32px;
  }
}

.uploader img{
  max-width: 464px;
  max-height: 100px;
  z-index:1;
  border:none;
}



.greyLogoBox {
  width: 100%;
  background: #EBEBEB;
  border: 1px solid #D7D7D7;
  text-align: center;
  height: 100px;
  padding-top: 22px;
  box-sizing: border-box;
}


#filePhoto{
  position:absolute;
  width:464px;
  height:100px;
  left:0;
  top:0;
  z-index:2;
  opacity:0;
  cursor:pointer;
}

до исправления моего кода:

function handleImage(e) {
              var reader = new FileReader();
              reader.onload = function (event) {
                  onclick="$('#filePhoto').click()"
                  $('.uploader img').attr('src',event.target.result);
              }
              reader.readAsDataURL(e.target.files[0]);
          }

Ошибка в консоли:

введите описание изображения здесь

Я решил это, удалив onclick="$('#filePhoto').click()" из тега div.

Ответ 16

Я столкнулся с той же проблемой Я разрешил это, удалив имя поля, которое использовалось дважды на ajax например

    jQuery.ajax({
    url : '/search-result',
    data : {
      searchField : searchField,
      searchFieldValue : searchField,
      nid    :  nid,
      indexName : indexName,
      indexType : indexType
    },
.....

Ответ 17

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

Предположим, у вас есть такие вложенные элементы:

<a href="#" id="profile-avatar-picker">
    <span class="fa fa-camera fa-2x"></span>
    <input id="avatar-file" name="avatar-file" type="file" style="display: none;" />
</a>

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

Так что этот код не удастся:

$('#profile-avatar-picker').on('click', (e) => {
    e.preventDefault();

    $('#profilePictureFile').trigger("click");
});

У вас есть два варианта, чтобы избежать этого:

  • Переместите ребенка наружу от родителя.
  • Примените функцию stopPropagation к дочернему элементу.

Ответ 18

У меня была эта ошибка, потому что у меня было две функции JS с одинаковым именем

Ответ 19

Если вы работаете с картами Google, проверьте, передаются ли последние значения в new google.maps.LatLng правильного формата. В моем случае они передавались как неопределенные.

Ответ 20

Проблема в моем случае заключается в том, что у меня есть дочерний маршрут с тем же путем, что и родительский:

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: '', redirectTo: 'home', pathMatch: 'prefix' },
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

Поэтому мне пришлось убрать линию детского маршрута

const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    children: [
      { path: 'home', loadChildren: './home.module#HomeModule' },
    ]
  }
];

Ответ 21

в моем случае я получаю эту ошибку при вызове ajax, и данные, которые я пытался передать этой переменной, не определены, то есть показывает эту ошибку, но не описывает эту переменную, не определенную. Я добавил определил, что переменная n получила значение.

Ответ 22

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

export default class DateUtils {
  static now = (): Date => {
    return DateUtils.now()
  }
}

Ответ 23

Это также может привести к Maximum call stack size exceeded:

var items = [];
[].push.apply(items, new Array(1000000)); //Bad

Тоже самое:

items.push(...new Array(1000000)); //Bad

Из документов Mozilla:

Но будьте осторожны: при использовании применять этот способ вы рискуете превысить ограничение длины аргумента движка JavaScript. Последствия применения функции со слишком большим количеством аргументов (например, более десятков тысяч аргументов) варьируются в зависимости от движков (JavaScriptCore имеет жестко запрограммированный предел аргументов 65536), потому что это предел (в действительности, даже характер любого чрезмерно большого стека) поведение) не уточняется. Некоторые двигатели будут выбрасывать исключения. Более пагубно, другие будут произвольно ограничивать количество аргументов, фактически передаваемых прикладной функции. Чтобы проиллюстрировать этот последний случай: если бы такой механизм имел ограничение в четыре аргумента (фактические пределы, конечно, значительно выше), это было бы так, как если бы аргументы 5, 6, 2, 3 были переданы для применения в приведенных выше примерах, а не полный массив.

Так что постарайтесь:

var items = [];
var newItems = new Array(1000000);
for(var i = 0; i < newItems.length; i++){
  items.push(newItems[i]);
}

Ответ 24

Столкнулись с той же проблемой, не могу понять, что неправильно начал обвинять Бабеля;)

Наличие кода, не возвращающего никаких исключений в браузерах:

if (typeof document.body.onpointerdown !== ('undefined' || null)) {

проблема была плохо создана || (или) part, поскольку babel создает свою собственную проверку типа:

function _typeof(obj){if(typeof Symbol==="function"&&_typeof(Symbol.iterator)==="symbol")

так что удаление

|| null

сделал вавилонскую транспиляцию.

Ответ 25

Еще один вариант, который вызывает эту ошибку, если вы конвертируете в json с сокетом.

export class User {
  constructor(socket: Socket, name: string) { 
     this.socket = socket;
     this.name   = name;
  }

   name   : string;
   socket : Socket;
}

...
let json: string = JSON.stringify(user);

Ответ 26

Я использую Devexpress Scheduler в Angular, и проблема заключается в неправильном использовании переменной, назначенной тегу источника данных планировщика.

Ответ 27

Иногда это происходит из-за типа данных для преобразования, например, у вас есть объект, который вы рассматриваете как строку.

socket.id в nodejs либо в js клиенте, например, не является строкой. чтобы использовать его как строку, вы должны добавить слово String перед:

String(socket.id);

Ответ 28

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

Объявление переменной исправило мою ошибку.

Ответ 29

T̶h̶i̶s̶ ̶c̶a̶n̶ ̶h̶a̶p̶p̶e̶n̶ ̶w̶h̶e̶n̶ ̶y̶o̶u̶ ̶t̶r̶y̶ ̶p̶u̶s̶h̶ ̶a̶n̶ ̶a̶r̶r̶a̶y̶ ̶i̶n̶t̶̶̶̶̶
let alerts = []; alerts.push(alerts);
Редактировать -
Я был неправ. Спасибо @melpomene за исправление.

Я получал сообщение об ошибке в консоли AWS cloud 9, и удаление вышеуказанного кода устранило проблему. Я вернусь к коду и выясню реальную причину его исправления и обновлю его здесь.