Uncaught rangeerror maximum call stack size exceeded как исправить

It means that somewhere in your code, you are calling a function which in turn calls another function and so forth, until you hit the call stack limit.

This is almost always because of a recursive function with a base case that isn’t being met.

Viewing the stack

Consider this code…

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

Here is the stack after a handful of calls…

Web Inspector

As you can see, the call stack grows until it hits a limit: the browser hardcoded stack size or memory exhaustion.

In order to fix it, ensure that your recursive function has a base case which is able to be met…

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

Community's user avatar

answered May 23, 2011 at 10:05

alex's user avatar

16

In my case, I was sending input elements instead of their values:

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

Instead of:

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

This froze my Chrome tab to a point it didn’t even show me the ‘Wait/Kill’ dialog for when the page became unresponsive…

answered Aug 13, 2016 at 23:55

FK-'s user avatar

FK-FK-

1,4421 gold badge10 silver badges17 bronze badges

7

You can sometimes get this if you accidentally import/embed the same JavaScript file twice, worth checking in your resources tab of the inspector.

double-beep's user avatar

double-beep

4,96617 gold badges32 silver badges41 bronze badges

answered Apr 23, 2012 at 1:58

lucygenik's user avatar

lucygeniklucygenik

1,6882 gold badges16 silver badges18 bronze badges

6

There is a recursive loop somewhere in your code (i.e. a function that eventually calls itself again and again until the stack is full).

Other browsers either have bigger stacks (so you get a timeout instead) or they swallow the error for some reason (maybe a badly placed try-catch).

Use the debugger to check the call stack when the error happens.

answered May 23, 2011 at 9:55

Aaron Digulla's user avatar

Aaron DigullaAaron Digulla

320k108 gold badges595 silver badges816 bronze badges

3

The problem with detecting stackoverflows is sometimes the stack trace will unwind and you won’t be able to see what’s actually going on.

I’ve found some of Chrome’s newer debugging tools useful for this.

Hit the Performance tab, make sure Javascript samples are enabled and you’ll get something like this.

It’s pretty obvious where the overflow is here! If you click on extendObject you’ll be able to actually see the exact line number in the code.

enter image description here

You can also see timings which may or may not be helpful or a red herring.

enter image description here


Another useful trick if you can’t actually find the problem is to put lots of console.log statements where you think the problem is. The previous step above can help you with this.

In Chrome if you repeatedly output identical data it will display it like this showing where the problem is more clearly. In this instance the stack hit 7152 frames before it finally crashed:

enter image description here

answered Mar 7, 2017 at 13:03

Simon_Weaver's user avatar

Simon_WeaverSimon_Weaver

138k81 gold badges638 silver badges680 bronze badges

1

In my case, I was converting a large byte array into a string using the following:

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

bytes contained several million entries, which is too big to fit on the stack.

answered Mar 24, 2017 at 16:48

Nate Glenn's user avatar

Nate GlennNate Glenn

6,4358 gold badges49 silver badges95 bronze badges

6

In my case, click event was propagating on child element. So, I had to put the following:

e.stopPropagation()

on click event:

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

Here is the html code:

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

Full Stack Alien's user avatar

answered Jan 16, 2017 at 15:36

Shahdat's user avatar

ShahdatShahdat

5,3034 gold badges37 silver badges37 bronze badges

This can also cause a Maximum call stack size exceeded error:

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

Same here:

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

From the Mozilla Docs:

But beware: in using apply this way, you run the risk of exceeding the
JavaScript engine’s argument length limit. The consequences of
applying a function with too many arguments (think more than tens of
thousands of arguments) vary across engines (JavaScriptCore has
hard-coded argument limit of 65536), because the limit (indeed even
the nature of any excessively-large-stack behavior) is unspecified.
Some engines will throw an exception. More perniciously, others will
arbitrarily limit the number of arguments actually passed to the
applied function. To illustrate this latter case: if such an engine
had a limit of four arguments (actual limits are of course
significantly higher), it would be as if the arguments 5, 6, 2, 3 had
been passed to apply in the examples above, rather than the full
array.

So try:

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

answered Jun 28, 2019 at 15:45

bendytree's user avatar

bendytreebendytree

12.9k10 gold badges73 silver badges90 bronze badges

1

Check the error details in the Chrome dev toolbar console, this will give you the functions in the call stack, and guide you towards the recursion that’s causing the error.

answered May 28, 2012 at 8:48

chim's user avatar

chimchim

8,3633 gold badges51 silver badges60 bronze badges

0

In my case, I basically forget to get the value of input.

Wrong

let name=document.getElementById('name');
param={"name":name}

Correct

let name=document.getElementById('name').value;
param={"name":name}

answered Aug 24, 2020 at 7:50

Aman's user avatar

AmanAman

2,2163 gold badges17 silver badges22 bronze badges

2

In my case, it was that I have 2 variables with the same name!

answered Sep 8, 2021 at 1:26

Nandostyle's user avatar

NandostyleNandostyle

3142 silver badges12 bronze badges

Nearly every answer here states that this can only be caused by an infinite loop. That’s not true, you could otherwise over-run the stack through deeply nested calls (not to say that’s efficient, but it’s certainly in the realm of possible). If you have control of your JavaScript VM, you can adjust the stack size. For example:

node --stack-size=2000

See also: How can I increase the maximum call stack size in Node.js

answered Feb 6, 2019 at 20:48

hayesgm's user avatar

hayesgmhayesgm

8,6201 gold badge38 silver badges40 bronze badges

We recently added a field to an admin site we are working on — contact_type… easy right? Well, if you call the select «type» and try to send that through a jquery ajax call it fails with this error buried deep in jquery.js Don’t do this:

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

The problem is that type:type — I believe it is us naming the argument «type» — having a value variable named type isn’t the problem. We changed this to:

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

And rewrote some_function.php accordingly — problem solved.

answered Apr 9, 2019 at 19:35

Scott's user avatar

ScottScott

6851 gold badge8 silver badges16 bronze badges

1

Sending input elements instead of their values will most likely resolve it like FK mentioned

answered Oct 17, 2021 at 10:08

El_boogy's user avatar

1

In my case, two jQuery modals were showing stacked on top of each other. Preventing that solved my problem.

answered Dec 28, 2016 at 21:23

Baz Guvenkaya's user avatar

Baz GuvenkayaBaz Guvenkaya

1,4823 gold badges17 silver badges26 bronze badges

Check if you have a function that calls itself. For example

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

answered Nov 22, 2018 at 13:13

onmyway133's user avatar

onmyway133onmyway133

45.2k28 gold badges254 silver badges262 bronze badges

For me as a beginner in TypeScript, it was a problem in the getter and the setter of _var1.

class Point2{
    
    constructor(private _var1?: number, private y?: number){}

    set var1(num: number){
        this._var1 = num  // problem was here, it was this.var1 = num
    }
    get var1(){
        return this._var1 // this was return this.var1
    }
}

answered Aug 4, 2020 at 14:20

ReemRashwan's user avatar

ReemRashwanReemRashwan

3413 silver badges8 bronze badges

dtTable.dataTable({
    sDom: "<'row'<'col-sm-6'l><'col-sm-6'f>r>t<'row'<'col-sm-6'i><'col-sm-6'p>>",
    "processing": true,
    "serverSide": true,
    "order": [[6, "desc"]],
    "columnDefs": [
        {className: "text-right", "targets": [2, 3, 4, 5]}
    ],
    "ajax": {
        "url": "/dt",
        "data": function (d) {
            d.loanRef = loanRef;
        }
    },
    "fnRowCallback": function (nRow, aData, iDisplayIndex, iDisplayIndexFull) {
        var editButton = '';
        // The number of columns to display in the datatable
        var cols = 8;
        // Th row element's ID
        var id = aData[(cols - 1)];
    }
});

In the data function above, I used the same name d.loanRef = loanRef but had not created a variable loanRef therefore recursively declaring itself.

Solution: Declare a loanRef variable or better still, use a different name from the one used on d.loanRef.

answered Mar 7, 2021 at 5:56

Kihats's user avatar

KihatsKihats

3,2565 gold badges29 silver badges46 bronze badges

Both invocations of the identical code below if decreased by 1 work in Chrome 32 on my computer e.g. 17905 vs 17904. If run as is they will produce the error «RangeError: Maximum call stack size exceeded». It appears to be this limit is not hardcoded but dependant on the hardware of your machine. It does appear that if invoked as a function this self-imposed limit is higher than if invoked as a method i.e. this particular code uses less memory when invoked as a function.

Invoked as a method:

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

ninja.chirp(17905);

Invoked as a function:

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

chirp(20889);

answered Feb 20, 2014 at 13:12

Elijah Lynn's user avatar

Elijah LynnElijah Lynn

12.1k10 gold badges59 silver badges90 bronze badges

I also faced similar issue here is the details
when uploading logo using dropdown logo upload box

<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;
}

before correction my code was :

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]);
          }

The error in console:

enter image description here

I solved it by removing onclick="$('#filePhoto').click()" from div tag.

answered Aug 3, 2017 at 8:37

spacedev's user avatar

spacedevspacedev

1,05613 silver badges13 bronze badges

2

I was facing same issue
I have resolved it by removing a field name which was used twice on ajax
e.g

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

answered Nov 8, 2017 at 7:57

Tajdar Khan Afridi's user avatar

The issue in my case is because I have children route with same path with the parent :

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

So I had to remove the line of the children route

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

answered Jul 25, 2018 at 17:06

Amine Harbaoui's user avatar

Amine HarbaouiAmine Harbaoui

1,2372 gold badges16 silver badges33 bronze badges

1

The issue might be because of recursive calls without any base condition for it to terminate.

Like in my case, if you see the below code, I had the same name for the API call method and the method which I used to perform operations post that API call.

const getData = async () => {
try {
  const response = await getData(props.convID);
  console.log("response", response);
 } catch (err) {
  console.log("****Error****", err);
}
};

So, basically, the solution is to remove this recursive call.

answered May 16, 2022 at 15:03

Akshay Chavan's user avatar

you can find your recursive function in crome browser,press ctrl+shift+j and then source tab, which gives you code compilation flow and you can find using break point in code.

answered Mar 12, 2014 at 8:01

Vishal Patel's user avatar

1

I know this thread is old, but i think it’s worth mentioning the scenario i found this problem so it can help others.

Suppose you have nested elements like this:

<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>

You cannot manipulate the child element events inside the event of its parent because it propagates to itself, making recursive calls until the exception is throwed.

So this code will fail:

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

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

You have two options to avoid this:

  • Move the child to the outside of the parent.
  • Apply stopPropagation function to the child element.

answered Jan 4, 2018 at 14:22

Weslley Ramos's user avatar

I had this error because I had two JS Functions with the same name

answered Jan 5, 2018 at 12:33

Monir Tarabishi's user avatar

Monir TarabishiMonir Tarabishi

7061 gold badge16 silver badges30 bronze badges

If you are working with google maps, then check if the lat lng are being passed into new google.maps.LatLng are of a proper format. In my case they were being passed as undefined.

answered Jan 30, 2018 at 13:25

User-8017771's user avatar

User-8017771User-8017771

1,4321 gold badge11 silver badges17 bronze badges

Sometimes happened because of convert data type , for example you have an object that you considered as string.

socket.id in nodejs either in js client as example, is not a string. to use it as string you have to add the word String before:

String(socket.id);

answered Jun 27, 2018 at 21:34

Hussein mahyoub's user avatar

in my case I m getting this error on ajax call and the data I tried to pass that variable haven’t defined, that is showing me this error but not describing that variable not defined. I added defined that variable n got value.

answered Aug 29, 2018 at 4:08

asifaftab87's user avatar

asifaftab87asifaftab87

1,28524 silver badges28 bronze badges

1

Время на прочтение
3 мин

Количество просмотров 121K

Проблема

Некоторое время назад в работе над клиентской (javascript) частью движка josi возникла, кстати, достаточно часто встречающаяся проблема переполнения стека:
Uncaught RangeError: Maximum call stack size exceeded (google chrome)
В статье рассматривается решение без использования setTimout или setInterval.

Суть

Причина такого поведения известна и понятна, и в той или иной форме всегда вызвана следующим. Классическая(прямая) рекурсия порождает цепочку последовательных вызовов, что соответственно ведет к наполнению стека вызовов, однако, стек вызовов браузера достаточно мал, в chrome на момент тестирования это 500 вызовов, в safari, если не ошибаюсь, тоже. В любом случае- это предельное значение, а значит его можно превысить и получить exception. Естественно, столь долгое выполнение кода не желательно в принципе, и этого стоит избегать. И все же лично мне не хочеться полагаться на удачу, не смотря на то, что ситуация в которой пришлось столкнуться с проблемой на продакшен возникнуть не должна, я потратил время на изучение данного вопроса.

Решение

Классическим решением (имею ввиду подавляющее количество статей предлагающих его) является использование косвенной рекурсии посредством: setTimeout либо setInterval.

В качестве примера приведу простенькую рекурсивную функция, единственное назначение которой рано или поздно вернуть Вам предел размера стека вместе с exeption о превышении этого предела…

function f(args) 
{
     var self=this;
     var k=args.k;

     //вызываем себя же
     try
     {
         f({k:k+1});
     }
     catch(ex)
     {
          alert(k);
     }
}

та же бесполезная функция, но теперь теоретически бесконечная, разве что k переполнится

function f(args) 
{
     var self=this;
     var k=args.k;
     
     //косвенно вызываем себя же, через посредника setTimeout
     setTimeout(function(){ f({k:k+1}) }, 0);
}

Текущая функция сразу завершается за счет использования для рекурсии посредника setTimout, а следующий вызов выполняется по событию.
Отрицательной стороной такого подхода является его крайне низкая производительность, несмотря на то, что мы указываем нулевую задержку. Вызвана функция будет в зависимости от браузера в среднем не раньше чем через 10 мс. Но ведь мы боремся с превышением стека вызовов, а значит наша функция вызывается сотни раз, что означает потерю в производительности ~1 с на каждые 100 вызовов. Детальное тестирование нашел тут.
Самое простое, что пришло в голову — организовать симбиоз из попеременного использования прямого и косвенного вызовов, чтобы при достижении некоторого значения счетчика прерывать стек косвенным вызовом. Отчасти такое решение сейчас и используется. Но здесь тоже все не так просто, особенно если рекурсия представлена петлей из нескольких функций.
Вот простенький пример отражающий суть такого решения:

var max_call_i=300;
function f(args) 
{
     var self=this;
     var k=args.k;
     var call_i=args.call_i
     //alert(k);

     if (call_i>=max_call_i)
     {     
            //косвенно вызываем себя же, через посредника setTimeout
            setTimeout(function(){ f({k:k+1, call_i:call_i+1}) }, 0);
     }
     else
     {
           //напрямую вызываем себя же
           f({k:k+1, call_i:call_i+1});
     }
}

В моем коде проблема возникла в шаблонизаторе, который как раз незадолго до этого был переписан согласно новой парадигме. Не хотелось отказываться от принятой архитектуры. В тоже время реальное падение производительности составило 20-30% — что было просто чудовищно. Предложенное выше решение тоже не идеал: сохранялось падение производительности на 5-7%. Это меня не устроило: много гуглил, и напал на то, что нужно.
А это тест от туда же, из которого видно что, предложенный подход, в сравнении с setTimeout 0, гораздо более производительный, что на практике дало не более 3% падения производительности в моем случае…

Данное решение основано на связке window.postMessage и element.addEventListener, для меня достаточно кроссбраузерно (ie8+).

Я переработал функцию из приведенной выше статьи в AMD модуль. Возможно, кому-то это будет полезным…

define([], function () 
{
        
	return
       {
		
		args:							//аргументы
		{
			indirect_call:
			{
				f_arr:[],
				msg_name:"indirect_call-message",
				handler_f:null,
			}
		},
		
		/*** работа с событиями ***/

		f_indirect_call:function(f)
		{
			var self=this;
			
			//если это первый вызов то создаем обработчик события и привязываем к window
			if (t_uti.f_is_empty(self.args.indirect_call.handler_f))
			{
				//создаем обработчик события
				self.args.indirect_call.handler_f=function(event) 
				{
					if (event.source == window && event.data == self.args.indirect_call.msg_name) 
					{
						event.stopPropagation();
						if (self.args.indirect_call.f_arr.length> 0) 
						{
							var f = self.args.indirect_call.f_arr.shift();
							f();
						}
					}
				}
				
				window.addEventListener("message", self.args.indirect_call.handler_f, true);
			}
			
			self.args.indirect_call.f_arr.push(f);
			window.postMessage(self.args.indirect_call.msg_name, "*");
		},
      };
});

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

  1. В первой функции находим на странице нужный элемент.
  2. Добавляем рамку с какой-то задержкой (чтобы она какое-то время была на экране).
  3. Вызываем функцию убирания рамки.
  4. Внутри второй функции находим тот же элемент на странице.
  5. Убираем рамку с задержкой.
  6. Вызываем первую функцию добавления рамки.

Код простой, поэтому делаем всё в одном файле:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Pulse</title>
	<style type="text/css">
	/*	рамка, которая будет моргать	*/
		.pulse { box-shadow: 0px 0px 4px 4px #AEA79F; }
	</style>
</head>
<body>
	<div id="pulseDiv"> 
    	<a href="#">
      		<div id="advisersDiv">
        		<img src="https://thecode.media/wp-content/uploads/2020/08/photo_2020-08-05-12.04.57.jpeg">
        	</div>
      	</a>
</div>
<!-- подключаем jQuery -->
<script src="https://yastatic.net/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
<!-- наш скрипт -->
<script type="text/javascript">
	// добавляем рамку
	function fadeIn() {
		// находим нужный элемент и добавляем рамку с задержкой
  	$('#pulseDiv').find('div#advisersDiv').delay(400).addClass("pulse");
  	// затем убираем рамку
  	fadeOut();
	};
	// убираем рамку
	function fadeOut() {
		// находим нужный элемент и убираем рамку с задержкой
   	$('#pulseDiv').find('div#advisersDiv').delay(400).removeClass("pulse");
   	// затем добавляем 
   	fadeIn();
	};
	// запускаем моргание рамки
	fadeIn();
</script>

</body>
</html>

Но при открытии страницы в браузере мы видим, что ничего не моргает, а в консоли появилась ошибка:

❌ Uncaught RangeError: Maximum call stack size exceeded

Что это значит: в браузере произошло переполнение стека вызовов и из-за этого он не может больше выполнять этот скрипт.

Переполнения стека простыми словами означает вот что:

  1. Когда компьютер что-то делает, он это делает последовательно — 1, 2, 3, 4.
  2. Иногда ему нужно отвлечься от одного и сходить сделать что-то другое — а, б, в, г, д. Получается что-то вроде 1, 2, 3 → а, б, в, г, д → 4.
  3. Вот эти переходы 3 → а и д → 4 — это компьютеру нужно запомнить, что он выполнял пункт 3, и потом к нему вернуться.
  4. Каждое запоминание, что компьютер бросил и куда ему нужно вернуться, — это называется «вызов».
  5. Вызовы хранятся в стеке вызовов. Это стопка таких ссылок типа «когда закончишь вот это, вернись туда».
  6. Стек не резиновый и может переполняться.

Что делать с ошибкой Uncaught RangeError: Maximum call stack size exceeded

Эта ошибка — классическая ошибка переполнения стека во время выполнения рекурсивных функций.

Рекурсия — это когда мы вызываем функцию внутри самой себя, но чуть с другими параметрами. Когда параметр дойдёт до конечного значения, цепочка разматывается обратно и функция собирает вместе все значения. Это удобно, когда у нас есть чёткий алгоритм подсчёта с понятными правилами вычислений.

В нашем случае рекурсия возникает, когда в конце обеих функций мы вызываем другую: 

  1. Функции начинают бесконтрольно вызывать себя бесконечное число раз.
  2. Стек вызовов начинает запоминать вызов каждой функции, чтобы, когда она закончится, вернуться к тому, что было раньше.
  3. Стек — это определённая область памяти, у которой есть свой объём.
  4. Вызовы не заканчиваются, и стек переполняется — в него больше нельзя записать вызов новой функции, чтобы потом вернуться обратно.
  5. Браузер видит всё это безобразие и останавливает скрипт.

То же самое будет, если мы попробуем запустить простую рекурсию слишком много раз:

Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded

Как исправить ошибку Uncaught RangeError: Maximum call stack size exceeded

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

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

<script type="text/javascript">
// добавляем рамку
function fadeIn() {
	// находим нужный элемент и добавляем рамку с задержкой
	$('#pulseDiv').find('div#advisersDiv').delay(400).addClass("pulse");
	// через секунду убираем рамку
	setTimeout(fadeOut,1000)
};
// убираем рамку
function fadeOut() {
	// находим нужный элемент и убираем рамку с задержкой
 	$('#pulseDiv').find('div#advisersDiv').delay(400).removeClass("pulse");
 	// через секунду добавляем рамку
	setTimeout(fadeIn,1000)
};
// запускаем моргание рамки
fadeIn();
</script>

Что означает ошибка Uncaught RangeError: Maximum call stack size exceeded

Вёрстка:

Кирилл Климентьев

The «Uncaught RangeError: Maximum call stack size exceeded» error occurs in JavaScript when you don’t specify an exit condition for your recursive function. Take the following as an example:

const test = () => test()

// ❌ This will throw "Uncaught RangeError: Maximum call stack size exceeded"
test()

Copied to clipboard!

This function will call itself indefinitely, causing the «Maximum call stack size exceeded» error. You may also come across this error in other forms, such as the below, but the cause will be the same.

"Uncaught InternalError: Too much recursion"

To fix the error, we will need to provide an exit condition. You can do this by wrapping the call inside a conditional statement. Take the following code as an example:

const countDown = num => {
    if (num > 0) {
        console.log(num)
        countDown(num - 1)
    }
}

Copied to clipboard!

This is also a recursive function that calls itself and will log out numbers until it reaches 0. Notice that we call the function with the «same argument — 1». This means that at a certain call, the condition will not be met, meaning we will stop executing the function. This way, we won’t reach the maximum call stack size, as we have an exit condition.

Get your weekly dose of webtips

Get access to 300+ webtips 💌

Level up your skills and master the art of frontend development with bite-sized tutorials.

We don’t spam. Unsubscribe anytime.

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.

Master JavaScript


Infinite loops

The «Maximum call stack size exceeded» error can not only happen with recursive functions, but with infinite loops as well. Most commonly, this can happen while using a while loop.

A common way to ensure that your while loop has an exit condition is to decrement a value at each iteration. Take a look at the following example:

i = 100

while (i--) {
    console.log(i)
}

Copied to clipboard!

Once i reaches 0, it will be evaluated as false, meaning we will stop executing the while loop. In this case, this is our exit condition.

Make sure you always define an exit condition to avoid running into infinite loops.

Want to learn more about recursion in JavaScript? Check out the below tutorial.

An Easy Way to Understand Recursion in JavaScript

An Easy Way to Understand Recursion in JavaScriptRecursion demonstrated through practical examplesLearn recursion in and out in JavaScript by learning how to generate file trees.

“RangeError: Maximum call stack size exceeded” in JavaScript is a common error related to the function call. The below explanations can help you know more about the cause of this error and how to fix it.

When do you get the error “RangeError: Maximum call stack size exceeded” in JavaScript?

This error indicates that the stack memory, created when any function is called in the JavaScript programming language, has been full of memory. Its size has exceeded the designed maximum limit; hence, no space can be added, meaning no more functions can be called. 

For example, you have a bad function which calls itself and hence it will run permanently:

function badFunction() {
	console.log("called");
	return badFunction();
}

Moreover, maybe you choose recursive method to solve the problem, but your code does not have a base case to prevent it loops forever, which means it have issues to recursion:

function factorial(x) {
	return factorial(x - 1) * x;
}

To fix this error, we suggest you the following solutions:

How to solve this error?

Avoid using recursion functions

As we have explained, recursion function will create a space in the stack memory, which will be deleted whenever the function has executed all the statements inside it. If you have a bad function like the examples below, you will often catch the error. Instead, we suggest you use the for loop to do some repeated work.

let n = 5;
let factorial = 1;

for (let i = 1; i < n; i++) {
	factorial = factorial * i;
}

console.log(factorial);

Output:

24

The above example used a for loop to calculate the factorial of 5 instead of using the recursion function. If you want to do a repetitive work that you don’t know how many times it will do, and it will stop at a condition given, then you can use the while loop instead:

let countdown = 10;

while (countdown != 0)
	console.log(countdown--);

Output:

10
9 
8 
7 
6 
5 
4 
3 
2 
1

Check the base case

Another way to overcome this problem is to check your base case in the recursion function. The base case of a recursive function is the case in which we know the answer and, therefore, is a way to return without making a recursive call. The base case is a must-have in any recursion function because it will stop that function from continuing permanently.

function factorial(x) {
	// Base case: factorial of 0 is always 1
	if (x == 0) {
		return 1;
	} else {
		return factorial(x - 1) * x;
	}
}

console.log(factorial(6))

Output

720

The base case for the factorial calculation problem is the case for 0, as 0! equals 1. However, some people use one as the base case instead of 0; hence, they will get the error when calling the factorial method on 0 or a negative number.

Summary

In this tutorial, we have helped you to deal with the error “RangeError: Maximum call stack size exceeded” in JavaScript. You can easily avoid this error by checking the correct base case and using a loop instead.

Maybe you are interested:

  • ReferenceError: document is not defined in Node.js
  • RangeError: Invalid time value in JavaScript

I’m Edward Anderson. My current job is as a programmer. I’m majoring in information technology and 5 years of programming expertise. Python, C, C++, Javascript, Java, HTML, CSS, and R are my strong suits. Let me know if you have any questions about these programming languages.


Name of the university: HCMUT
Major: CS
Programming Languages: Python, C, C++, Javascript, Java, HTML, CSS, R

Понравилась статья? Поделить с друзьями:
  • Как исправить ошибку в перечисленном налоге
  • Как найти хорошие сайты чтобы скачать фильмы
  • Как найти волков valheim
  • Как исправить ошибку е247
  • Как найти цену за баррель