console.log () không đồng bộ hay đồng bộ hóa?


93

Tôi hiện đang đọc Async Javascript của Trevor Burnham. Đây là một cuốn sách tuyệt vời cho đến nay.

Anh ấy nói về đoạn mã này và console.log là 'không đồng bộ' trong bảng điều khiển Safari và Chrome. Thật không may, tôi không thể lặp lại điều này. Đây là mã:

var obj = {}; 
console.log(obj); 
obj.foo = 'bar';
// my outcome: Object{}; 'bar';
// The book outcome: {foo:bar};

Nếu điều này không đồng bộ, tôi sẽ đoán trước kết quả là kết quả của sách. console.log () được đặt trong hàng đợi sự kiện cho đến khi tất cả mã được thực thi, sau đó nó được chạy và nó sẽ có thuộc tính thanh.

Nó xuất hiện mặc dù nó đang chạy đồng bộ.

Tôi đang chạy mã này sai? Console.log có thực sự không đồng bộ không?


@thefourtheye: Không, vì vậy có lẽ tôi nên xóa bình luận của mình.
cookie monster,

1
Tôi đã thấy nó xảy ra trong Chrome. Nếu bạn console.log một đối tượng đơn giản và sau đó ngay lập tức thay đổi một cái gì đó trong đối tượng, console.log()thì không phải lúc nào cũng hiển thị giá trị cũ. Giải pháp xung quanh nếu điều này xảy ra với bạn là chuyển đổi bất cứ thứ gì bạn đang cố gắng console.log()thành một chuỗi không thay đổi được để không bị vấn đề này. Vì vậy, theo kinh nghiệm, console.log()có một số vấn đề không đồng bộ có thể liên quan đến việc sắp xếp dữ liệu qua các ranh giới quy trình. Đây không phải là hành vi dự định, nhưng là một số tác dụng phụ của cách console.log()hoạt động bên trong (cá nhân tôi coi đó là một lỗi).
jfriend00


1
@bergi, tôi chỉ mất 10 phút để tìm bản dupe này (mặc dù tôi biết tên chính xác), có thể là do nó bị trùng lặp. Không lẽ chúng ta chỉ hoán đổi bản sao, để bản còn lại là bản dupe ...?
Jonas Wilms

1
@JonasWilms Bây giờ tôi đã mở lại câu hỏi này (xem lịch sử ). Tôi không nghĩ chúng là bản sao của nhau, tôi sử dụng Bảng điều khiển JavaScript của Chrome có lười đánh giá mảng không? làm mục tiêu chuẩn cho các vấn đề cụ thể liên quan đến một mảng.
Bergi

Câu trả lời:


114

console.logkhông được tiêu chuẩn hóa, vì vậy hành vi là khá không xác định và có thể được thay đổi dễ dàng từ khi phát hành cho đến khi phát hành các công cụ dành cho nhà phát triển. Cuốn sách của bạn có thể đã lỗi thời, câu trả lời của tôi có thể sẽ sớm thôi.

Đối với mã của chúng tôi, nó không tạo ra bất kỳ sự khác biệt nào cho dù console.logkhông đồng bộ hay không, nó không cung cấp bất kỳ loại gọi lại nào hoặc tương tự như vậy; và các giá trị bạn chuyển luôn được tham chiếu và tính toán tại thời điểm bạn gọi hàm.

Chúng tôi không thực sự biết điều gì sẽ xảy ra sau đó (OK, chúng tôi có thể, vì Firebug, Chrome Devtools và Opera Dragonfly đều là mã nguồn mở). Bàn điều khiển sẽ cần lưu trữ các giá trị đã ghi ở đâu đó và nó sẽ hiển thị chúng trên màn hình. Kết xuất chắc chắn sẽ xảy ra không đồng bộ (được điều chỉnh để cập nhật giới hạn tốc độ), cũng như các tương tác trong tương lai với các đối tượng đã ghi trong bảng điều khiển (như mở rộng thuộc tính đối tượng).

Vì vậy, bảng điều khiển có thể sao chép (tuần tự hóa) các đối tượng có thể thay đổi mà bạn đã ghi nhật ký hoặc nó sẽ lưu trữ các tham chiếu đến chúng. Cái đầu tiên không hoạt động tốt với các đối tượng sâu / lớn. Ngoài ra, ít nhất kết xuất ban đầu trong bảng điều khiển có thể sẽ hiển thị trạng thái "hiện tại" của đối tượng, tức là trạng thái khi nó được đăng nhập - trong ví dụ của bạn, bạn thấy Object {}.

Tuy nhiên, khi bạn mở rộng đối tượng để kiểm tra thêm các thuộc tính của nó, có khả năng bảng điều khiển sẽ chỉ lưu trữ một tham chiếu đến đối tượng của bạn và các thuộc tính của nó, và việc hiển thị chúng bây giờ sẽ hiển thị trạng thái hiện tại (đã bị đột biến) của chúng. Nếu bạn nhấp vào +, bạn sẽ có thể xem thuộc bartính trong ví dụ của mình.

Đây là ảnh chụp màn hình đã được đăng trong báo cáo lỗi để giải thích "bản sửa lỗi" của họ:

Vì vậy, một số giá trị có thể được tham chiếu rất lâu sau khi chúng được ghi lại và việc đánh giá chúng khá lười biếng ("khi cần"). Ví dụ nổi tiếng nhất về sự khác biệt này được xử lý trong câu hỏi Bảng điều khiển JavaScript của Chrome có lười đánh giá mảng không?

Một cách giải quyết là đảm bảo luôn ghi nhật ký các ảnh chụp nhanh được tuần tự hóa của các đối tượng của bạn, ví dụ: bằng cách thực hiện console.log(JSON.stringify(obj)). Tuy nhiên, điều này sẽ chỉ hoạt động đối với các đối tượng không tròn và khá nhỏ. Xem thêm Làm cách nào để thay đổi hành vi mặc định của console.log trong Safari? .

Giải pháp tốt hơn là sử dụng các điểm ngắt để gỡ lỗi, nơi việc thực thi hoàn toàn dừng lại và bạn có thể kiểm tra các giá trị hiện tại tại mỗi điểm. Chỉ sử dụng ghi nhật ký với dữ liệu có thể tuần tự hóa và bất biến.


2
tôi đã gặp vấn đề tương tự với console.log không được đồng bộ hóa. bằng cách sử dụng JSON.stringify đã sửa nó cho tôi
russiansummer

Kể từ năm 2019, chúng ta có thể nói rằng console.lognó vẫn không đồng bộ trong Chrome vì nó đã 8 năm tuổi (xem stackoverflow.com/questions/7389069/… ), điều duy nhất thay đổi là bây giờ Chrome xuất ra ảnh chụp nhanh của đối tượng tham chiếu tại thời gian bạn gọi console.log(nếu bạn mở rộng đối tượng đã ghi, bạn sẽ thấy các thuộc tính và giá trị cuối cùng của nó sau các thao tác đột biến bạn đã thực hiện sau đó console.log) hay console.logthực sự là đồng bộ?
tonix

@tonix Có, hành vi này khó có thể thay đổi do những lý do đã nêu trong câu trả lời của tôi. Nó không phải là một lỗi, nó chỉ là cách một trình gỡ lỗi / kiểm tra tương tác hoạt động.
Bergi

Nếu bạn sử dụng JSON.parse(JSON.stringify(obj))như cũng được đề cập trong nhận xét ở đây, bạn sẽ nhận được một ảnh chụp nhanh ở dạng đối tượng, thay vì một chuỗi.
Héo

TL; DR.way way TL
Rick O'Shea

2

Đây thực sự không phải là một câu trả lời cho câu hỏi, nhưng nó có thể hữu ích cho những người tình cờ gặp bài đăng này và đã quá lâu để đưa ra nhận xét:

window.console.logSync = (...args) => {
  try {
    args = args.map((arg) => JSON.parse(JSON.stringify(arg)));
    console.log(...args);
  } catch (error) {
    console.log('Error trying to console.logSync()', ...args);
  }
};

Điều này tạo ra một phiên bản giả đồng bộ của console.log, nhưng với cùng những cảnh báo như đã đề cập trong câu trả lời được chấp nhận.

Vì hiện tại, hầu hết các trình duyệt console.logđều không đồng bộ theo một cách nào đó, bạn có thể muốn sử dụng một chức năng như thế này trong một số trường hợp nhất định.


0

Khi sử dụng console.log:

a = {}; a.a=1;console.log(a);a.b=function(){};
// without b
a = {}; a.a=1;a.a1=1;a.a2=1;a.a3=1;a.a4=1;a.a5=1;a.a6=1;a.a7=1;a.a8=1;console.log(a);a.b=function(){};
// with b, maybe
a = {}; a.a=function(){};console.log(a);a.b=function(){};
// with b

trong tình huống đầu tiên, đối tượng đủ đơn giản, vì vậy console có thể 'xâu chuỗi' nó sau đó trình bày cho bạn; nhưng trong các tình huống khác, a quá 'phức tạp' để 'stringify' vì vậy giao diện điều khiển sẽ hiển thị cho bạn đối tượng trong bộ nhớ thay vào đó, và vâng, khi bạn nhìn vào nó, b đã được gắn với a.


Tôi biết câu hỏi này đã được 3 năm nhưng hiện tại tôi đang gặp phải vấn đề tương tự - tuần tự hóa đối tượng không hoạt động với tôi vì nó quá phức tạp. Tôi đang bắt gặp một sự kiện đang cố gắng truy cập dữ liệu của nó nhưng bằng cách nào đó nó không có dữ liệu trong mã nhưng trong console.log thì nó có dữ liệu.
Skeec
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.