2011-07-27 32 views
326

Câu hỏi này được hỏi nhiều lần trong SO. Nhưng tôi vẫn không thể kiếm được.Cách trả về giá trị từ hàm gọi lại không đồng bộ?

Tôi muốn nhận được một số giá trị từ gọi lại. Hãy xem kịch bản bên dưới để làm rõ.

function foo(address){ 

     // google map stuff 
     geocoder.geocode({ 'address': address}, function(results, status) { 
      results[0].geometry.location; // I want to return this value 
     }) 

    } 
    foo(); //result should be results[0].geometry.location; value 

Nếu tôi cố gắng trả lại giá trị đó chỉ nhận được "không xác định". Tôi đã làm theo một số ý tưởng từ SO, nhưng vẫn không thành công.

Đó là:

function foo(address){ 
    var returnvalue;  
    geocoder.geocode({ 'address': address}, function(results, status) { 
     returnvalue = results[0].geometry.location; 
    }) 
    return returnvalue; 
} 
foo(); //still undefined 
+11

Bất kỳ ai đến đây [** vui lòng đọc câu hỏi này trước **] (http://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-ajax-call). Nó giải thích cách giải quyết vấn đề này một cách hiệu quả. –

+0

** [Tại sao biến của tôi không bị thay đổi sau khi tôi sửa đổi nó bên trong một hàm? - Tham chiếu mã không đồng bộ] (http://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) ** cũng cung cấp một lời giải thích tổng quát hơn, chi tiết hơn về vấn đề này. –

+0

Sử dụng Q hoặc bất kỳ biến thể nào của nó, như thư viện $ q đi kèm với angularJs. Và không bao giờ nhìn lại. Các hàm không đồng bộ ngay lập tức trả về không xác định. Vì vậy, không bao giờ lãng phí thời gian của bạn đang cố gắng làm công cụ trên không xác định. Cũng không bao giờ sử dụng từ khóa 'return' trong các hàm async của bạn, như bạn thường làm. Thay vào đó hãy sử dụng lời hứa hoãn lại. deferred.resolve (STUFF bạn muốn làm), sau đó bạn có thể đơn giản trả về điều đó, 'return deferred.promise; '. :) – ISONecroMAn

Trả lời

336

Điều này là không thể vì bạn không thể quay trở lại từ một cuộc gọi không đồng bộ bên trong một phương thức đồng bộ.

Trong trường hợp này bạn cần phải vượt qua một callback để foo sẽ nhận giá trị trả về

function foo(address, fn){ 
    geocoder.geocode({ 'address': address}, function(results, status) { 
    fn(results[0].geometry.location); 
    }); 
} 

foo("address", function(location){ 
    alert(location); // this is where you get the return value 
}); 

Có điều là, nếu một chức năng gọi nội là không đồng bộ, sau đó tất cả các chức năng 'gói quà' cuộc gọi này phải cũng không đồng bộ để trả về một câu trả lời.

Nếu bạn có nhiều cuộc gọi lại, bạn có thể cân nhắc việc thực hiện việc giảm và sử dụng số promise library like Q.

+3

:) Nó không mạnh, nó chỉ là như thế nào. Ngay khi bạn sử dụng một phương thức async để truyền dữ liệu, toàn bộ chuỗi chức năng trở nên không đồng bộ. –

+0

Nếu chuỗi các hàm async thao tác một đối tượng, giả sử một đối tượng 'đồ thị'. Có anyway tôi có thể nhận được một tham chiếu đến đối tượng đó để gọi một cái gì đó như cập nhật() vào nó? – user2483724

+2

Upvote cho cuối cùng làm cho điều này có ý nghĩa. –

18

Nó làm cho không có ý nghĩa để trở về giá trị từ một callback. Thay vào đó, hãy thực hiện tác vụ "foo()" mà bạn muốn làm bên trong số gọi lại của bạn.

Gọi lại không đồng bộ được gọi bởi trình duyệt hoặc bởi một số khung như thư viện mã hóa địa lý của Google khi sự kiện diễn ra. Không có chỗ cho các giá trị trả về. Hàm gọi lại có thể trả lại giá trị, nói cách khác, nhưng mã gọi hàm sẽ không chú ý đến giá trị trả về.

14

Nếu bạn tình cờ được sử dụng jQuery, bạn có thể muốn cung cấp cho này một shot: http://api.jquery.com/category/deferred-object/

Nó cho phép bạn trì hoãn việc thực hiện các chức năng gọi lại cho đến khi yêu cầu ajax (hoặc bất kỳ hoạt động async) được hoàn thành . Điều này cũng có thể được sử dụng để gọi một cuộc gọi lại khi một số yêu cầu ajax đã hoàn tất.

Các vấn đề liên quan