Hướng dẫn javascript set global variable in callback - javascript đặt biến toàn cục trong lệnh gọi lại

Một từ Trả lời: Sự không đồng bộ.asynchronicity.

Lời nói đầu

Chủ đề này đã được lặp lại ít nhất một vài ngàn lần, ở đây, trong Stack Overflow. Do đó, trước hết tôi muốn chỉ ra một số tài nguyên cực kỳ hữu ích:

  • Câu trả lời của @Felix Kling cho "Làm cách nào để trả lại phản hồi từ một cuộc gọi không đồng bộ?". Xem câu trả lời tuyệt vời của anh ấy giải thích các luồng đồng bộ và không đồng bộ, cũng như phần "mã tái cấu trúc". @Benjamin Gruenbaum cũng đã nỗ lực rất nhiều để giải thích sự không đồng bộ trong cùng một chủ đề.
    @Benjamin Gruenbaum has also put a lot of effort explaining asynchronicity in the same thread.

  • Câu trả lời của @Matt Esch cho "Nhận dữ liệu từ fs.readfile" cũng giải thích sự không đồng bộ cực kỳ tốt một cách đơn giản.


Câu trả lời cho câu hỏi trong tay

Hãy theo dõi hành vi phổ biến trước tiên. Trong tất cả các ví dụ, outerScopeVar được sửa đổi bên trong một hàm. Chức năng đó rõ ràng không được thực thi ngay lập tức, nó đang được gán hoặc thông qua như một đối số. Đó là những gì chúng tôi gọi là một cuộc gọi lại.callback.

Bây giờ câu hỏi là, khi nào cuộc gọi đó được gọi là?

Nó phụ thuộc vào trường hợp. Hãy cố gắng theo dõi một số hành vi phổ biến một lần nữa:

  • img.onload có thể được gọi vào đôi khi trong tương lai, khi (và nếu) hình ảnh đã tải thành công.
  • setTimeout có thể được gọi vào đôi khi trong tương lai, sau khi sự chậm trễ đã hết hạn và thời gian chờ đã không bị hủy bởi clearTimeout. Lưu ý: Ngay cả khi sử dụng 0 làm độ trễ, tất cả các trình duyệt đều có giới hạn độ trễ thời gian chờ tối thiểu (được chỉ định là 4ms trong thông số kỹ thuật HTML5).
  • Cuộc gọi lại của JQuery ________ 8 có thể được gọi vào đôi khi trong tương lai, khi (và nếu) yêu cầu AJAX đã được hoàn thành thành công.
  • fs.readFile của Node.js có thể được gọi vào đôi khi trong tương lai, khi tệp đã được đọc thành công hoặc ném lỗi.

Trong mọi trường hợp, chúng tôi có một cuộc gọi lại có thể chạy đôi khi trong tương lai. "Thỉnh thoảng trong tương lai" này là những gì chúng ta gọi là dòng chảy không đồng bộ.asynchronous flow.

Thực thi không đồng bộ được đẩy ra khỏi dòng chảy đồng bộ. Đó là, mã không đồng bộ sẽ không bao giờ thực thi trong khi ngăn xếp mã đồng bộ đang thực thi. Đây là ý nghĩa của JavaScript là một luồng đơn.never execute while the synchronous code stack is executing. This is the meaning of JavaScript being single-threaded.

Cụ thể hơn, khi động cơ JS không hoạt động - không thực hiện một chồng mã đồng bộ (a) - nó sẽ thăm dò ý kiến ​​cho các sự kiện có thể đã kích hoạt các cuộc gọi không đồng bộ (ví dụ: thời gian chờ hết hạn, nhận được phản hồi mạng) và thực hiện chúng. Đây được coi là vòng lặp sự kiện.

Đó là, mã không đồng bộ được tô sáng trong các hình dạng màu đỏ được vẽ bằng tay chỉ có thể thực thi sau khi tất cả các mã đồng bộ còn lại trong các khối mã tương ứng của chúng đã được thực thi:

Hướng dẫn javascript set global variable in callback - javascript đặt biến toàn cục trong lệnh gọi lại

Nói tóm lại, các hàm gọi lại được tạo đồng bộ nhưng được thực hiện không đồng bộ. Bạn không thể dựa vào việc thực hiện một chức năng không đồng bộ cho đến khi bạn biết nó đã được thực hiện và làm thế nào để làm điều đó?

Nó là đơn giản, thực sự. Logic phụ thuộc vào thực thi chức năng không đồng bộ nên được bắt đầu/được gọi từ bên trong hàm không đồng bộ này. Ví dụ, việc di chuyển các ____10 và

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
1 quá bên trong hàm gọi lại sẽ đưa ra kết quả dự kiến, bởi vì kết quả có sẵn tại thời điểm đó.

Thực hiện logic gọi lại của riêng bạn

Thường thì bạn cần phải làm nhiều việc hơn với kết quả từ một hàm không đồng bộ hoặc làm những việc khác nhau với kết quả tùy thuộc vào nơi hàm không đồng bộ đã được gọi. Hãy giải quyết một ví dụ phức tạp hơn một chút:

var outerScopeVar;
helloCatAsync();
alert(outerScopeVar);

function helloCatAsync() {
    setTimeout(function() {
        outerScopeVar = 'Nya';
    }, Math.random() * 2000);
}

Lưu ý: Tôi đang sử dụng setTimeout với độ trễ ngẫu nhiên là hàm không đồng bộ chung, ví dụ tương tự áp dụng cho AJAX,

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
3,
// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
4 và bất kỳ luồng không đồng bộ nào khác.
I'm using setTimeout with a random delay as a generic asynchronous function, the same example applies to Ajax,
// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
3,
// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
4 and any other asynchronous flow.

Ví dụ này rõ ràng phải chịu vấn đề tương tự như các ví dụ khác, nó không chờ đợi cho đến khi chức năng không đồng bộ thực thi.

Hãy giải quyết nó khi thực hiện một hệ thống gọi lại của riêng chúng tôi. Trước hết, chúng ta thoát khỏi cái outerScopeVar xấu xí đó hoàn toàn vô dụng trong trường hợp này. Sau đó, chúng tôi thêm một tham số chấp nhận một đối số chức năng, gọi lại của chúng tôi. Khi hoạt động không đồng bộ kết thúc, chúng tôi gọi cuộc gọi lại này vượt qua kết quả. Việc thực hiện (vui lòng đọc các nhận xét theo thứ tự):

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

Mã mã của ví dụ trên:

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
console.log("1. function called...")
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    console.log("5. result is: ", result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    console.log("2. callback here is the function passed as argument above...")
    // 3. Start async operation:
    setTimeout(function() {
    console.log("3. start async operation...")
    console.log("4. finished async operation, calling the callback, passing the result...")
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}

Thông thường trong các trường hợp sử dụng thực tế, API DOM và hầu hết các thư viện đã cung cấp chức năng gọi lại (triển khai

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
6 trong ví dụ chứng minh này). Bạn chỉ cần vượt qua chức năng gọi lại và hiểu rằng nó sẽ thực hiện khỏi luồng đồng bộ và tái cấu trúc mã của bạn để phù hợp với điều đó.

Bạn cũng sẽ nhận thấy rằng do bản chất không đồng bộ, không thể

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
7 một giá trị từ một luồng không đồng bộ trở lại dòng đồng bộ trong đó cuộc gọi lại được xác định, vì các cuộc gọi lại không đồng bộ được thực thi lâu sau khi mã đồng bộ đã hoàn thành thực thi.

Thay vì

// 1. Call helloCatAsync passing a callback function,
//    which will be called receiving the result from the async operation
helloCatAsync(function(result) {
    // 5. Received the result from the async function,
    //    now do whatever you want with it:
    alert(result);
});

// 2. The "callback" parameter is a reference to the function which
//    was passed as argument from the helloCatAsync call
function helloCatAsync(callback) {
    // 3. Start async operation:
    setTimeout(function() {
        // 4. Finished async operation,
        //    call the callback passing the result as argument
        callback('Nya');
    }, Math.random() * 2000);
}
7ing giá trị từ một cuộc gọi lại không đồng bộ, bạn sẽ phải sử dụng mẫu gọi lại hoặc ... lời hứa.

Hứa hẹn

Mặc dù có nhiều cách để giữ cho địa ngục gọi lại với Vanilla JS, những lời hứa đang ngày càng phổ biến và hiện đang được chuẩn hóa trong ES6 (xem Promise - MDN).

Lời hứa (a.k.a. Futures) cung cấp một cách đọc tuyến tính hơn, và do đó dễ chịu, đọc mã không đồng bộ, nhưng giải thích toàn bộ chức năng của chúng nằm ngoài phạm vi của câu hỏi này. Thay vào đó, tôi sẽ để lại những tài nguyên tuyệt vời này cho những người quan tâm:

  • Lời hứa JavaScript - HTML5 Rocks
  • Bạn đang thiếu điểm hứa - Domenic.me

Đọc thêm tài liệu về sự không đồng bộ của JavaScript

  • Nghệ thuật của nút - gọi lại giải thích mã không đồng bộ và gọi lại rất tốt với các ví dụ Vanilla JS và mã Node.js.

Lưu ý: Tôi đã đánh dấu câu trả lời này là wiki cộng đồng, do đó bất kỳ ai có ít nhất 100 danh tiếng đều có thể chỉnh sửa và cải thiện nó! Xin vui lòng cải thiện câu trả lời này, hoặc gửi một câu trả lời hoàn toàn mới nếu bạn cũng muốn. I've marked this answer as Community Wiki, hence anyone with at least 100 reputations can edit and improve it! Please feel free to improve this answer, or submit a completely new answer if you'd like as well.

Tôi muốn biến câu hỏi này thành một chủ đề kinh điển để trả lời các vấn đề không đồng bộ không liên quan đến AJAX (có cách trả lại câu trả lời từ một cuộc gọi AJAX? !!

Chức năng gọi lại có thể truy cập biến toàn cầu không?

Điều này có nghĩa là cuộc gọi lại là một đóng cửa. Việc đóng có quyền truy cập vào phạm vi của hàm chứa, do đó hàm gọi lại có thể truy cập các biến của các hàm chứa và thậm chí các biến từ phạm vi toàn cầu.the callback function can access the containing functions' variables, and even the variables from the global scope.

Bạn có thể đặt các biến toàn cầu trong JavaScript không?

Các biến toàn cầu toàn cầu có thể được truy cập từ bất cứ nơi nào trong chương trình JavaScript.Các biến được khai báo với VAR, LET và Const khá giống nhau khi được khai báo bên ngoài một khối.Global variables can be accessed from anywhere in a JavaScript program. Variables declared with var , let and const are quite similar when declared outside a block.

Làm thế nào để bạn truy cập biến bên trong chức năng gọi lại JavaScript?

3 Phương pháp truy cập đúng điều này bên trong một cuộc gọi lại..
Sử dụng một hàm mũi tên.Các chức năng mũi tên JavaScript đã được giới thiệu trong Ecmascript 6. ....
Tạo một biến khác để lưu trữ đối tượng này.....
Liên kết rõ ràng điều này với một đối tượng ..

Callback () trong javascript là gì?

Một cuộc gọi lại JavaScript là một hàm sẽ được thực thi sau khi một chức năng khác hoàn thành thực thi.Một định nghĩa chính thức hơn sẽ là - bất kỳ hàm nào được truyền dưới dạng đối số cho một hàm khác để nó có thể được thực thi trong hàm khác được gọi là hàm gọi lại.a function which is to be executed after another function has finished execution. A more formal definition would be - Any function that is passed as an argument to another function so that it can be executed in that other function is called as a callback function.