2010-10-15 45 views
9

Ví dụ này là JavaScript, vì đó là nơi tôi đang sử dụng hầu hết các cuộc gọi lại. Tôi muốn hiểu cách họ làm việc ở mức độ thấp.Các cuộc gọi lại luôn không đồng bộ?

Trong ví dụ bên dưới, tôi hy vọng mọi thứ sẽ xảy ra theo thứ tự và "gọi lại" sẽ xảy ra sau "bước 3" và trước "bước 4." Điều này có ý nghĩa với tôi, vì mọi thứ đều được thực hiện theo thứ tự trên một luồng thực thi duy nhất. Không có thủ đoạn. Điều duy nhất đặc biệt là bạn đã chuyển một hàm tới một hàm khác.

function main() { 
    console.log("step 1"); 
    console.log("step 2"); 
    doSomething(myCallBack); 
    console.log("step 4"); 
} 

function doSomething(f) { 
    accessTheDatabase(); // this could take a while 
    console.log("step 3"); 
    f(); // done - now call back 
} 

function myCallBack() { 
    console.log("calling back!"); 
} 

Làm thế nào bạn sẽ làm cho doSomething không đồng bộ để "bước 4" có thể được thực hiện trước khi, hoặc song song với "bước 3"?

Tôi giả định rằng nếu doSomething được gọi bằng cách nào đó không đồng bộ, nó sẽ phải nằm trên một chuỗi khác nhau, phải không? Và nếu như vậy, khi nó kết thúc và sau đó gọi myCallBack, không gọi lại xảy ra trên chủ đề thứ hai hoặc trên chủ đề chính? Nếu nó xảy ra trên luồng chính, tại sao luồng thứ hai lại cần một con trỏ tới hàm gọi lại? Cuộc gọi giữa các luồng hoạt động như thế nào?

+0

Tôi cho rằng điều này là * không * đang chạy trong trình duyệt, phải không? Bởi vì trong trình duyệt, bất kỳ cuộc gọi AJAX nào là không đồng bộ ... –

+2

@Dean, trước hết các yêu cầu XHR có thể bằng đồng bộ (tùy thuộc vào các tham số yêu cầu). Thứ hai, nếu bạn đọc câu hỏi (và nhìn vào mã ví dụ của nó), nó không phải là về Ajax. – eyelidlessness

+0

@Dean nó có thể đang chạy trong trình duyệt hay không. Tôi quan tâm nhất trong việc tìm ra liệu chức năng gọi lại được thực thi trên luồng chính hay luồng thứ hai đã được chuyển qua con trỏ hàm gọi lại như một tham số. –

Trả lời

11

WebWorkers sang một bên, mô hình lập trình JavaScript trong trình duyệt hoàn toàn đơn luồng. Bạn có thể thực hiện cuộc gọi của bạn một chút không đồng bộ bằng cách sử dụng window.setTimeout:

window.setTimeout(doSomething, 0, myCallBack); 

này có hiệu quả đặt cuộc gọi doSomething(myCallBack) vào hàng đợi hẹn giờ, và sau 0 hoặc nhiều mili giây trôi qua, nó cuối cùng sẽ nhận được viện dẫn. Tuy nhiên, như với tất cả các cuộc gọi không đồng bộ trong JavaScript, bạn phải từ bỏ ngữ cảnh thực thi trước khi bất kỳ cuộc gọi lại không đồng bộ nào có thể được gọi; có nghĩa là hàng đợi hẹn giờ sẽ không được xử lý (và do đó doSomething(myCallBack) sẽ không được gọi) cho đến khi hàm main() của bạn kết thúc, giả sử đó là phần cuối của JavaScript của bạn.

Một hậu quả không may của phương pháp tiếp cận dựa trên setTimeout này là doSomething(myCallBack) không được gọi song song cùng với console.log("step 4"). Mặt khác, hãy xem xét XMLHttpRequest.send; sau khi thực hiện cuộc gọi này, phần còn lại của JS của bạn có thể tiếp tục thực thi trong khi trình duyệt phát ra yêu cầu HTTP. Kịch bản của bạn cần phải hoàn thành việc thực thi trước khi trình xử lý onreadystatechange có thể thực thi, nhưng hầu hết công việc kết nối HTTP có thể xảy ra song song trong khi JS thực hiện.

+0

Trong trường hợp 'XMLHttpRequest.send', tôi giả sử điều đó xảy ra trên một chuỗi khác. Khi nó được thực hiện và trình xử lý 'onreadystatechange' thực hiện, luồng nào xảy ra? –

+1

Điều này xảy ra trên chuỗi JavaScript chính. Thực hiện khôn ngoan, điều này có thể là bất kỳ chủ đề nào, nhưng khái niệm JavaScript (và DOM, cho vấn đề đó) thực hiện trong một chuỗi đơn lẻ. – ide

+1

Tôi đoán phần khó hiểu là nó được gọi là "gọi lại". Điều đó, với tôi, nói "đây là một chức năng, hãy gọi nó khi bạn làm xong việc của bạn. Tôi sẽ tự làm việc của mình." Khi thực sự, trình duyệt kết thúc cuộc gọi AJAX và sau đó ngắt chuỗi chính (thông qua cơ chế nào ??) và chính chuỗi đó sẽ gọi hàm mà nó đã đăng ký làm cuộc gọi lại. Tôi có đúng không? –

0

Bạn sẽ cần nhiều luồng thực thi để thực hiện việc này, mà tôi không tin rằng bạn có thể làm trong Javascript (mặc dù sửa tôi nếu tôi sai). Tuy nhiên, nếu bạn đang viết một chương trình C/C++, hãy xem gói pthreads (hoặc libdispatch trên Mac OS X 10.6).

Chỉnh sửa: tìm kiếm của Google cho "chuỗi javascript" sẽ bật lên một số kết quả có thể thú vị.

0

Sử dụng gọi lại theo cách của bạn (tên khai báo hàm hoặc tên biến biểu thức hàm làm đối số cho hàm khác), chúng là đồng bộ. Để làm cho chúng không đồng bộ, bạn có thể bọc chúng trong một setTimeout.

+0

@trinithis, tôi thế nào? – eyelidlessness

5

Hmmm .. có gì đó không đúng (tôi đã thực hiện v chút JavaScript): bạn chuyển myCallBack vào hàm doSomething() nhưng bạn không gọi lại? Bạn sẽ phải có một cuộc gọi đến f() bên trong doSomething() hoặc chuyển nó đến một hàm khác mà sẽ gọi nó trở lại sau khi thao tác dài của bạn hoàn tất .. Và không có callback nào vốn không đồng bộ - trong trường hợp bạn đang chạy nó trên cùng một luồng (ngay cả khi accessTheDatabase() là không đồng bộ trong trường hợp đó nó sẽ ngay lập tức trở lại!) - vì vậy nó sẽ vẫn đi Bước 1, Bước 2, Bước 3, Bước 4. Tôi tin rằng bạn muốn:

function main() { 
    console.log("step 1"); 
    console.log("step 2"); 
    doSomething(myCallBack); 
    console.log("step 4"); 
} 

function doSomething(f) { 
    accessTheDatabase(f); // assuming this is an asynchronous operation and calls the callback f once done 
} 

function myCallBack() { 
    console.log("step 3"); 
} 

Trong câu trả lời cho phần thứ hai của câu hỏi của bạn: gọi lại sẽ được chạy trên đó từng sợi bạn đang gọi nó từ - để chạy một callback trên một chủ đề mà bạn sẽ phải join() mà thread đầu tiên sau đó gọi() hoặc begininvoke() gọi lại - mặc dù có thể đã có một số cách được xây dựng để gửi cuộc gọi lại của bạn vào một chuỗi các thứ cần chạy trên chuỗi bạn muốn chạy nó (thường là trường hợp có chủ đề giao diện người dùng) LƯU Ý: Có thể đã có quyền truy cậpTheDatabase() chạy gọi lại trên chuỗi được gọi là - sử dụng một trong các phương pháp được đề cập ở trên ...

+0

Bạn nói đúng! Cảm ơn cho bắt. –

+0

Niềm vui của tôi, đánh dấu nó là câu trả lời nếu nó là :) – markmnl

+0

câu trả lời cập nhật cho phần thứ hai của câu hỏi của bạn - chuỗi nào được chạy trên đó – markmnl

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