2015-03-06 47 views
32

Khi tôi hiểu lời hứa là một thứ có thể giải quyết() hoặc từ chối() nhưng tôi ngạc nhiên khi biết rằng mã trong lời hứa vẫn tiếp tục thực hiện sau khi giải quyết hoặc từ chối được gọi.Tại sao javascript ES6 Promises tiếp tục thực hiện sau khi giải quyết?

Tôi đã xem xét giải quyết hoặc từ chối là phiên bản thoát hoặc trả lại không đồng bộ thân thiện, điều này có thể tạm dừng tất cả thực thi chức năng ngay lập tức.

Ai đó có thể giải thích ý nghĩ đằng sau lý do tại sao các ví dụ sau đây cho thấy đôi khi console.log sau khi một cuộc gọi quyết tâm:

var call = function() { 
    return new Promise(function(resolve, reject) { 
     resolve(); 
     console.log("Doing more stuff, should not be visible after a resolve!"); 
    }); 
}; 

call().then(function() { 
    console.log("resolved"); 
}); 

jsbin

+5

câu hỏi hợp lý, nhưng sau đó một lần nữa, JS chỉ thực hiện một tuyên bố sau khi khác như bạn nói đến nó. 'resolve()' không phải là câu lệnh điều khiển JS mà kỳ diệu sẽ có tác dụng 'return', nó chỉ là một lời gọi hàm, và vâng, việc thực hiện tiếp tục sau nó. –

+0

Đây là một câu hỏi hay và thậm chí sau khi đọc tất cả các câu trả lời, tôi không chắc chắn về các phương pháp hay nhất ... –

Trả lời

61

JavaScript có khái niệm là "run to completion". Trừ khi có lỗi xảy ra, một hàm sẽ được thực hiện cho đến khi đạt được câu lệnh return hoặc kết thúc của nó. Mã khác bên ngoài chức năng không thể can thiệp vào đó (trừ khi, một lần nữa, một lỗi được ném ra).

Nếu bạn muốn resolve() để thoát khỏi chức năng initialiser của bạn, bạn cần phải thêm vào trước nó bằng cách return:

return new Promise(function(resolve, reject) { 
    return resolve(); 
    console.log("Not doing more stuff after a return statement"); 
}); 
+0

Hi Felix - Tôi nghĩ rằng đây chỉ là một phần của câu chuyện - phần khác là 'resolve()' chính nó là một hàm async. Như chúng ta đã thấy trong câu trả lời khác (đã bị xóa), một số người tin rằng gọi 'giải quyết' sẽ lập tức chạy bất kỳ cuộc gọi lại nào. – Alnitak

+2

@Alnitak 'resolve' chính nó không phải là không đồng bộ, nó hoàn toàn đồng bộ. Mặc dù sử dụng API ES6 nghiêm ngặt, nó không thể quan sát được cho dù đó là đồng bộ hay không đồng bộ. – Esailija

+0

@Esailija ok, có lẽ tôi không rõ ràng. Một số người tin rằng gọi 'giải quyết' sẽ dẫn đến bất kỳ callbacks đã đăng ký được gọi ngay lập tức như vậy mà họ là một phần của ngăn xếp cuộc gọi hiện tại. Điều đó không đúng, thay vào đó nó chỉ xếp hàng các callbacks (và bạn nói đúng, nó không phải là không đồng bộ, nhưng nó chỉ làm việc của nó và chấm dứt ngay lập tức) – Alnitak

14

Các callbacks đó sẽ được gọi khi bạn resolve một lời hứa vẫn còn theo yêu cầu của đặc tả được gọi là không đồng bộ. Điều này là để đảm bảo hành vi nhất quán khi sử dụng lời hứa kết hợp các hành động đồng bộ và không đồng bộ.

Vì vậy, khi bạn gọi resolve gọi lại là xếp hàng và thực thi chức năng sẽ tiếp tục ngay lập tức với bất kỳ mã nào sau cuộc gọi resolve().

Chỉ khi vòng lặp sự kiện JS được trả về, điều khiển có thể gọi lại được xóa khỏi hàng đợi và thực sự được gọi.

+0

Hàng đợi gọi lại được ghi lại trong Thông số A + hoặc trong ES6? – thefourtheye

+4

@thefourtheye: Đặc điểm vòng lặp sự kiện thực sự là một phần của [HTML5] (http://www.w3.org/TR/html5/webappapis.html#event-loops) ngay bây giờ. ES6 định nghĩa một phương thức bên trong được gọi là [** 'EnqueueJob' **] (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-enqueuejob), được gọi bởi [**' .then '**] (https://people.mozilla.org/~jorendorff/es6-draft.html#sec-promise.prototype.then). –

+0

@FelixKling Oh thanks :) – thefourtheye

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