Vượt quá kích thước ngăn xếp cuộc gọi tối đa


533

Tôi đang sử dụng tệp thư viện JavaScript Trực tiếp từ xa (DWR) và tôi chỉ gặp lỗi trong Safari (máy tính để bàn và iPad)

Nó nói rằng

Đã vượt quá kích thước ngăn xếp cuộc gọi tối đa.

Chính xác thì lỗi này có nghĩa là gì và nó có dừng xử lý hoàn toàn không?

Ngoài ra bất kỳ sửa chữa cho Safaritrình duyệt (Trên thực tế iPad Safari, nó nói

JS: thực thi vượt quá thời gian chờ

mà tôi giả sử là vấn đề ngăn xếp cuộc gọi tương tự)


2
tôi đã gặp lỗi này khi cố gắng gửi các biến (mà không khai báo chúng), thông qua dataajax. Đã sửa lỗi bằng cách khai báo các biến.
phpfresher

Câu trả lời:


621

Điều đó có nghĩa là ở đâu đó trong mã của bạn, bạn đang gọi một hàm lần lượt gọi một hàm khác và cứ thế, cho đến khi bạn đạt giới hạn ngăn xếp cuộc gọi.

Điều này hầu như luôn luôn là do một hàm đệ quy với trường hợp cơ sở không được đáp ứng.

Xem ngăn xếp

Hãy xem xét mã này ...

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

Đây là chồng sau một số cuộc gọi ...

Thanh tra web

Như bạn có thể thấy, ngăn xếp cuộc gọi phát triển cho đến khi nó đạt đến một giới hạn: kích thước ngăn xếp được mã hóa cứng của trình duyệt hoặc cạn kiệt bộ nhớ.

Để khắc phục, hãy đảm bảo rằng hàm đệ quy của bạn có trường hợp cơ sở có thể được đáp ứng ...

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

6
Thx rất nhiều cho điều đó..Vậy có cách nào / công cụ mà tôi có thể giới hạn ngăn xếp đang cạn kiệt..Anh, vì đây là một tệp thư viện khổng lồ và không phải do tôi tạo ra, tôi không hoàn toàn biết mọi thứ có thể sẽ sai ..
testndtv

52
@Oliver Nếu bạn phải chạy một chức năng gần 300 nghìn tỷ lần, có lẽ bạn đã làm sai điều gì đó.
ceejayoz

3
@Oliver - bạn có thể muốn xem xét lập trình động - tôi đoán là bạn không có nhiều giải pháp độc đáo, bạn đang lặp lại các bước, vì vậy bạn có thể cần lập trình nó thành thời gian đa thức thay vì bậc hai. vi.wikipedia.org/wiki/Docate_programming
newshorts

4
@Akhoy Trong một hàm thông thường có, nhưng hãy nghĩ về một hàm đệ quy. Nó gọi một (chính nó) và để lại địa chỉ trả về của ngăn xếp cũ trên ngăn xếp (nếu không thì PC sẽ biết đi đâu?) Điều này tất nhiên gọi lại lần nữa, mỗi lần đẩy một địa chỉ trả lại vào ngăn xếp. Khi điều này biến mất do một trường hợp cơ bản không có khả năng được đáp ứng trong thế kỷ tiếp theo, bạn sẽ bị tràn ngăn xếp.
alex

5
Mã của bạn chạy cùng phân đoạn không hiệu quả 134217728 lần. Không đùa đâu. Bạn nên sử dụng các toán tử bitwise để bạn có thể hủy 9 cấp độ vòng lặp thành một cấp độ vòng lặp.
Jack Giffin

82

Đôi khi bạn có thể nhận được điều này nếu bạn vô tình nhập / nhúng cùng một tệp JavaScript hai lần, đáng để kiểm tra trong tab tài nguyên của trình kiểm tra.


9
Vấn đề này thường xảy ra khi bạn vô tình nhập / nhúng cùng một tệp JS hai lần. Quá trình chính xác gây ra vòng lặp đệ quy không phải là điều tôi quan tâm để suy đoán, tuy nhiên tôi sẽ cho rằng nó giống như lái hai chiếc xe giống hệt nhau ở tốc độ 100mph qua cùng một cổng thu phí.
lucygenik

3
Tôi không nghĩ đây là trường hợp. Nếu hai loại hàm hoặc biến giống nhau được nhúng, cái sau sẽ ghi đè các định nghĩa trước đó.
ssudaraka

Vâng ... Tôi không thực sự biết tại sao nó xảy ra hoặc quá trình là gì, tôi sẽ có mặc dù nó cũng sẽ ghi đè.
lucygenik

Đến bữa tiệc muộn một chút, nhưng sẽ tưởng tượng rằng đó là khi mã nằm ngoài bất kỳ chức năng nào, cả hai sẽ được thực thi trong hai tệp JS và một người có thể sẽ không ghi đè lên nhau vì chúng nằm ngoài bất kỳ chức năng nào.
Cillian Collins

1
@lucygenik lần sau bạn muốn cẩn thận hơn khi phê duyệt các chỉnh sửa troll trên bài đăng của bạn. Bài đăng này gần như đã bị xóa dưới dạng thư rác (kiểm tra lịch sử)
Jean-François Fabre

57

Trong trường hợp của tôi, tôi đã gửi các phần tử đầu vào thay vì các giá trị của chúng:

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

Thay vì:

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

Điều này đã đóng băng tab Chrome của tôi đến một điểm mà nó thậm chí còn không hiển thị cho tôi hộp thoại 'Chờ / Giết' khi trang không phản hồi ...


3
Tôi tự hỏi tại sao không có ngoại lệ cho lỗi như vậy ... Cảm ơn!
Džuris

Cảm ơn rất nhiều, điều này đã cứu tôi
Eme Hado

Tôi đã định thêm điều này như một giải pháp có thể. Tôi vừa mới làm điều này chính xác lol
Michael Buchok

31

Có một vòng lặp đệ quy ở đâu đó trong mã của bạn (tức là một hàm cuối cùng tự gọi đi gọi lại cho đến khi ngăn xếp đầy).

Các trình duyệt khác có ngăn xếp lớn hơn (vì vậy bạn sẽ có thời gian chờ thay thế) hoặc chúng nuốt lỗi vì một số lý do (có thể là lỗi thử bắt được đặt không tốt).

Sử dụng trình gỡ lỗi để kiểm tra ngăn xếp cuộc gọi khi xảy ra lỗi.


Thx rất nhiều cho câu trả lời của bạn. Trên IE / FF, mã dường như chạy tốt..Chỉ trong Safari Safari trên máy tính để bàn và iPad Safari, tôi gặp lỗi. Trên thực tế, tệp JS không phải là sáng tạo của riêng tôi, mà là tệp thư viện (từ DWR engine.js) .. directwebremote.org Ngoài ra khi bạn nói "trình gỡ lỗi để kiểm tra ngăn xếp cuộc gọi", tôi phải làm thế nào khi sử dụng Trình kiểm tra Safari?
testndtv

Tôi không có kinh nghiệm với Safari Inspector. Hãy thử mở trình gỡ lỗi JavaScript và tải trang của bạn. Trình gỡ lỗi sẽ dừng khi ném lỗi chưa được xử lý. Nếu điều đó không hiệu quả, hãy hỏi về siêu người dùng hoặc quản trị trang web (xem dưới cùng của trang)
Aaron Digulla

có 2 chức năng được đặt tên giống nhau !! ĐỪNG!
jharris8567

16

Vấn đề với việc phát hiện stackoverflows đôi khi dấu vết stack sẽ bị bung ra và bạn sẽ không thể thấy những gì đang thực sự xảy ra.

Tôi đã tìm thấy một số công cụ gỡ lỗi mới hơn của Chrome hữu ích cho việc này.

Nhấn Performance tab, đảm bảo Javascript samplesđược kích hoạt và bạn sẽ nhận được một cái gì đó như thế này.

Đó là khá rõ ràng nơi tràn vào đây! Nếu bạn nhấp vào, extendObjectbạn sẽ có thể thực sự thấy số dòng chính xác trong mã.

nhập mô tả hình ảnh ở đây

Bạn cũng có thể thấy thời gian có thể có hoặc không hữu ích hoặc cá trích đỏ.

nhập mô tả hình ảnh ở đây


Một mẹo hữu ích khác nếu bạn thực sự không thể tìm ra vấn đề là đặt nhiều console.logcâu mà bạn nghĩ là có vấn đề. Bước trước ở trên có thể giúp bạn với điều này.

Trong Chrome nếu bạn liên tục xuất dữ liệu giống hệt nhau, nó sẽ hiển thị như thế này cho thấy vấn đề rõ ràng hơn. Trong trường hợp này, ngăn xếp đã chạm tới 7152 khung trước khi nó bị sập:

nhập mô tả hình ảnh ở đây


13

Trong trường hợp của tôi, tôi đã chuyển đổi một mảng byte lớn thành một chuỗi bằng cách sử dụng như sau:

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

bytes chứa vài triệu mục, quá lớn để phù hợp với ngăn xếp.


Tôi cũng có vấn đề tương tự với cùng một dòng !! thanx
ksh

Vì vậy, giải pháp tốt nhất để chuyển đổi mảng byte lớn là gì ??
ksh

6
@KarthikHande Bạn phải thực hiện trong vòng lặp for thay vì trong một cuộc gọi. var uintArray = new Uint16Array(bytes); var converted = []; uintArray.forEach(function(byte) {converted.push(String.fromCharCode(byte))});
Nate Glenn

Làm cách nào để chuyển đổi nó thành JSON? Tôi đã thử JSON.parse nhưng nó không hoạt động ... Tôi đang sử dụng Uintl8Array
ksh

@KarthikHande Tôi không thể nói mà không thấy toàn bộ vấn đề. Vui lòng mở một câu hỏi khác với tất cả các chi tiết.
Nate Glenn

6

Trong trường hợp của tôi, nhấp vào sự kiện đã được tuyên truyền trên phần tử con. Vì vậy, tôi đã phải đặt như sau:

e.stopPropagation ()

khi nhấp vào sự kiện:

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

Đây là mã html:

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

5

Kiểm tra chi tiết lỗi trong bảng điều khiển thanh công cụ Chrome, điều này sẽ cung cấp cho bạn các chức năng trong ngăn xếp cuộc gọi và hướng dẫn bạn về đệ quy gây ra lỗi.



3

Gần như mọi câu trả lời ở đây đều nói rằng điều này chỉ có thể được gây ra bởi một vòng lặp vô hạn. Điều đó không đúng, nếu không, bạn có thể chạy quá mức ngăn xếp thông qua các cuộc gọi được lồng vào nhau (không nói là hiệu quả, nhưng chắc chắn là trong lĩnh vực có thể). Nếu bạn có quyền kiểm soát máy ảo JavaScript, bạn có thể điều chỉnh kích thước ngăn xếp. Ví dụ:

node --stack-size=2000

Xem thêm: Làm cách nào tôi có thể tăng kích thước ngăn xếp cuộc gọi tối đa trong Node.js


2

Trong trường hợp của tôi, hai phương thức jQuery đã được hiển thị xếp chồng lên nhau. Ngăn chặn điều đó giải quyết vấn đề của tôi.


2

Gần đây chúng tôi đã thêm một trường vào một trang quản trị mà chúng tôi đang làm việc - contact_type ... dễ dàng phải không? Chà, nếu bạn gọi "loại" chọn và cố gắng gửi nó thông qua một cuộc gọi ajax jquery thì không thành công với lỗi này được chôn sâu trong jquery.js Đừng làm điều này:

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

Vấn đề là loại: loại - Tôi tin rằng chúng ta đặt tên cho đối số là "loại" - có một biến giá trị có tên là loại không phải là vấn đề. Chúng tôi đã thay đổi điều này thành:

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

Và viết lại some_function.php cho phù hợp - vấn đề đã được giải quyết.


1

Kiểm tra nếu bạn có một chức năng gọi chính nó. Ví dụ

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

1

Điều này cũng có thể gây ra Maximum call stack size exceededlỗi:

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

Tương tự ở đây:

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

Từ tài liệu Mozilla :

Nhưng hãy cẩn thận: khi sử dụng áp dụng theo cách này, bạn sẽ gặp rủi ro vượt quá giới hạn độ dài đối số của công cụ JavaScript. Hậu quả của việc áp dụng một hàm có quá nhiều đối số (nghĩ rằng hơn hàng chục nghìn đối số) khác nhau giữa các công cụ (JavaScriptCore có giới hạn đối số được mã hóa cứng là 65536), bởi vì giới hạn (thực sự là bản chất của bất kỳ ngăn xếp quá lớn nào hành vi) là không xác định. Một số động cơ sẽ ném một ngoại lệ. Nghiêm trọng hơn, những người khác sẽ tùy ý giới hạn số lượng đối số thực sự được truyền cho hàm được áp dụng. Để minh họa trường hợp sau này: nếu một công cụ như vậy có giới hạn bốn đối số (giới hạn thực tế dĩ nhiên cao hơn đáng kể), thì sẽ như thể các đối số 5, 6, 2, 3 đã được thông qua để áp dụng trong các ví dụ trên, chứ không phải là mảng đầy đủ.

Hãy thử

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

0

Cả hai cách gọi mã giống hệt bên dưới nếu giảm 1 công việc trong Chrome 32 trên máy tính của tôi, ví dụ 17905 so với 17904. Nếu chạy như vậy, chúng sẽ tạo ra lỗi "RangeError: Đã vượt quá kích thước ngăn xếp cuộc gọi tối đa". Dường như giới hạn này không bị mã hóa cứng mà phụ thuộc vào phần cứng của máy. Có vẻ như nếu được gọi như là một hàm thì giới hạn tự áp đặt này cao hơn so với nếu được gọi như một phương thức, tức là mã cụ thể này sử dụng ít bộ nhớ hơn khi được gọi như một hàm.

Được gọi là một phương thức:

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

ninja.chirp(17905);

Được gọi là một hàm:

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

chirp(20889);

0

bạn có thể tìm thấy hàm đệ quy của mình trong trình duyệt crome, nhấn ctrl + shift + j và sau đó là tab nguồn, cung cấp cho bạn luồng biên dịch mã và bạn có thể tìm thấy bằng cách sử dụng điểm ngắt trong mã.


Tuy nhiên, đôi khi, thật khó để tìm ra lỗi bắt nguồn từ đâu. Chúng tôi có rất nhiều JavaScript trên trang web của chúng tôi.
Mathias Lykkegaard Lorenzen

0

Tôi cũng gặp phải vấn đề tương tự ở đây là các chi tiết khi tải lên logo bằng hộp tải lên logo thả xuống

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

trước khi sửa mã của tôi là:

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

Lỗi trong giao diện điều khiển:

nhập mô tả hình ảnh ở đây

Tôi đã giải quyết nó bằng cách xóa onclick="$('#filePhoto').click()"khỏi thẻ div.


Nơi bạn đã thêm nhấp chuột ()
Tsea

0

Tôi đã phải đối mặt với cùng một vấn đề Tôi đã giải quyết nó bằng cách xóa tên trường được sử dụng hai lần trên ajax, vd

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

0

Tôi biết chủ đề này đã cũ, nhưng tôi nghĩ rằng đáng để đề cập đến kịch bản tôi đã tìm thấy vấn đề này để nó có thể giúp đỡ người khác.

Giả sử bạn có các phần tử lồng nhau như thế này:

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

Bạn không thể thao tác các sự kiện phần tử con bên trong sự kiện của cha mẹ nó vì nó tự truyền cho chính nó, thực hiện các cuộc gọi đệ quy cho đến khi ngoại lệ được ném.

Vì vậy, mã này sẽ thất bại:

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

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

Bạn có hai lựa chọn để tránh điều này:

  • Di chuyển con ra bên ngoài của cha mẹ.
  • Áp dụng hàm stopPropagation cho phần tử con.


0

Nếu bạn đang làm việc với google maps, thì hãy kiểm tra xem lat lng đang được chuyển vào new google.maps.LatLngcó đúng định dạng không. Trong trường hợp của tôi, chúng đã được thông qua là không xác định.


0

Vấn đề trong trường hợp của tôi là vì tôi có con cái có cùng đường dẫn với cha mẹ:

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

Vì vậy, tôi đã phải loại bỏ các tuyến đường trẻ em

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

0

trong trường hợp của tôi, tôi gặp lỗi này trong cuộc gọi ajax và dữ liệu tôi đã cố gắng vượt qua biến đó chưa được xác định, điều đó cho tôi thấy lỗi này nhưng không mô tả biến đó không được xác định. Tôi đã thêm định nghĩa rằng biến n có giá trị.


bản thân tôi cũng bị bỏng theo cách tương tự, trong trường hợp của tôi là do tôi đánh máy một tên biến ... thực sự giống như vậy.
dùng2366842

0

Đã đi đến cùng một vấn đề, coulnd đã không tìm ra những gì sai bắt đầu đổ lỗi cho Babel;)

Có mã không trả lại bất kỳ ngoại lệ nào trong trình duyệt:

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

vấn đề được tạo ra tồi tệ | | (hoặc) một phần khi babel tạo kiểu kiểm tra riêng:

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

vì vậy loại bỏ

|| null

làm cho babel transpilation làm việc.


0

Trong trường hợp của tôi, tôi đã nhầm, tôi đã gán cùng một tên biến và cho hàm val "class_routine_id"

var class_routine_id = $("#class_routine_id").val(class_routine_id);

nó nên giống như:

 var class_routine_id = $("#class_routine_id").val(); 


0

Tôi đang sử dụng React-Native 0.61.5 cùng với ( npm 6.9.0 & nút 10.16.1 )

Trong khi tôi cài đặt bất kỳ thư viện mới nào trong Dự án, tôi đã nhận được một

(ví dụ: npm install @ Reac-navigation / local --save)

Vượt quá kích thước ngăn xếp cuộc gọi tối đa

cho điều đó, tôi cố gắng

sudo npm cache sạch - Force

(Lưu ý: - Lệnh bên dưới thường mất thời gian từ 1 đến 2 phút tùy thuộc vào kích thước bộ đệm npm của bạn )


-1

Đôi khi xảy ra do chuyển đổi loại dữ liệu, ví dụ bạn có một đối tượng mà bạn coi là chuỗi.

socket.id trong nodejs hoặc trong js client làm ví dụ, không phải là một chuỗi. để sử dụng nó dưới dạng chuỗi, bạn phải thêm chuỗi từ trước:

String(socket.id);

-1

Tôi đã cố gắng gán một biến, một giá trị, khi biến đó chưa được khai báo.

Khai báo biến đã sửa lỗi của tôi.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.