Tương lai JavaScript so với lời hứa
Qua. Philipp Haller, Aleksandar Prokopec, Heather Miller, Viktor Klang, Roland Kuhn và Vojin Jovanovic Show
Giới thiệuHợp đồng tương lai cung cấp một cách lý luận về việc thực hiện nhiều hoạt động song song– một cách hiệu quả và không bị chặn. Một 2 là một đối tượng giữ chỗ cho một giá trị có thể chưa tồn tại. Nói chung, giá trị của Tương lai được cung cấp đồng thời và sau đó có thể được sử dụng. Soạn các tác vụ đồng thời theo cách này có xu hướng dẫn đến mã song song nhanh hơn, không đồng bộ, không chặnTheo mặc định, các hợp đồng tương lai và lời hứa không bị chặn, sử dụng các cuộc gọi lại thay vì các hoạt động chặn thông thường. Để đơn giản hóa việc sử dụng các lệnh gọi lại cả về mặt cú pháp và khái niệm, Scala cung cấp các bộ kết hợp như 3, 4 và 5 được sử dụng để soạn hợp đồng tương lai theo cách không chặn. Vẫn có thể chặn - đối với những trường hợp thực sự cần thiết, hợp đồng tương lai có thể bị chặn (mặc dù điều này không được khuyến khích)Một tương lai điển hình trông như thế này
Hoặc với thành ngữ hơn
Cả hai đoạn mã đều ủy thác việc thực thi 6 cho một 7 và thể hiện kết quả tính toán trong 8Bối cảnh thực hiệnTương lai và Lời hứa xoay quanh 7s, chịu trách nhiệm thực hiện các tính toánMột 7 tương tự như một Executor. có thể tự do thực hiện các tính toán trong một luồng mới, trong một luồng gộp hoặc trong luồng hiện tại (mặc dù việc thực hiện tính toán trong luồng hiện tại không được khuyến khích – hãy nói thêm về điều đó bên dưới)Gói 1 được đưa ra khỏi hộp với triển khai 7, một nhóm luồng tĩnh toàn cầu. Cũng có thể chuyển đổi một 3 thành một 7. Cuối cùng, người dùng có thể tự do mở rộng đặc điểm 7 để triển khai bối cảnh thực thi của riêng họ, mặc dù điều này chỉ nên được thực hiện trong một số trường hợp hiếm hoiBối cảnh thực thi toàn cầu 6 là một 7 được hỗ trợ bởi ForkJoinPool. Nó là đủ cho hầu hết các tình huống nhưng cần phải cẩn thận. Một 8 quản lý một số luồng giới hạn (số lượng luồng tối đa được gọi là mức xử lý song song). Số lượng tính toán chặn đồng thời chỉ có thể vượt quá mức xử lý song song nếu mỗi lệnh gọi chặn được bao bọc bên trong một lệnh gọi 9 (thêm về điều đó bên dưới). Mặt khác, có nguy cơ nhóm luồng trong bối cảnh thực thi toàn cầu bị bỏ đói và không thể tiến hành tính toánTheo mặc định, 6 đặt mức độ song song của nhóm liên kết rẽ nhánh cơ bản của nó thành số lượng bộ xử lý có sẵn (). Cấu hình này có thể được ghi đè bằng cách đặt một (hoặc nhiều) thuộc tính VM sau
Mức độ song song sẽ được đặt thành 4 miễn là nó vẫn nằm trong khoảng 5Như đã nêu ở trên, 8 có thể tăng số lượng luồng vượt quá 7 của nó khi có tính toán chặn. Như đã giải thích trong API 8, điều này chỉ khả thi nếu nhóm được thông báo rõ ràng
May mắn thay, gói đồng thời cung cấp một cách thuận tiện để làm như vậy
Lưu ý rằng 9 là một cấu trúc chung sẽ được thảo luận sâu hơnCuối cùng nhưng không kém phần quan trọng, bạn phải nhớ rằng 8 không được thiết kế cho các hoạt động ngăn chặn lâu dài. Ngay cả khi được thông báo bằng 9, nhóm có thể không sinh ra công nhân mới như bạn mong đợi và khi công nhân mới được tạo, chúng có thể lên tới 32767. Để cung cấp cho bạn một ý tưởng, đoạn mã sau sẽ sử dụng 32000 chủ đề
Nếu bạn cần bao bọc các hoạt động chặn lâu dài, chúng tôi khuyên bạn nên sử dụng một 7 chuyên dụng, chẳng hạn bằng cách bao bọc một Java 3Điều chỉnh Trình thực thi JavaSử dụng phương pháp 4, bạn có thể bọc một Java 3 thành một 7. Ví dụ
Bối cảnh thực thi đồng bộNgười ta có thể muốn có một 7 chạy các phép tính trong luồng hiện tại
Điều này nên tránh vì nó đưa ra thuyết không tất định trong việc thực hiện tương lai của bạn
Lệnh gọi 8 có thể thực thi trong luồng của 9 hoặc trong luồng chính và do đó có thể là không đồng bộ hoặc đồng bộ. Như đã giải thích ở đây, một cuộc gọi lại không nên là cả haiMột 2 là một đối tượng chứa một giá trị có thể trở nên khả dụng tại một thời điểm nào đó. Giá trị này thường là kết quả của một số tính toán khác
Hoàn thành có thể có một trong hai hình thức
Một 2 có một thuộc tính quan trọng mà nó chỉ có thể được chỉ định một lần. Khi một đối tượng 2 được cung cấp một giá trị hoặc một ngoại lệ, nó sẽ có hiệu lực bất biến – nó không bao giờ có thể bị ghi đèCách đơn giản nhất để tạo một đối tượng tương lai là gọi phương thức 8 bắt đầu tính toán không đồng bộ và trả về một tương lai chứa kết quả của phép tính đó. Kết quả sẽ có sẵn khi tương lai hoàn thànhLưu ý rằng 9 là một loại biểu thị các đối tượng trong tương lai, trong khi đó 8 là một phương thức tạo và lên lịch cho một phép tính không đồng bộ, sau đó trả về một đối tượng trong tương lai sẽ được hoàn thành với kết quả của phép tính đóĐiều này được thể hiện rõ nhất thông qua một ví dụ Giả sử rằng chúng ta muốn sử dụng API giả định của một số mạng xã hội phổ biến để lấy danh sách bạn bè cho một người dùng nhất định. Chúng tôi sẽ mở một phiên mới và sau đó gửi yêu cầu lấy danh sách bạn bè của một người dùng cụ thể
3Ở trên, trước tiên chúng tôi nhập nội dung của gói 1 để hiển thị loại 2. Chúng tôi sẽ sớm giải thích lần nhập thứ haiSau đó, chúng tôi khởi tạo một biến phiên mà chúng tôi sẽ sử dụng để gửi yêu cầu đến máy chủ, sử dụng phương pháp 03 giả định. Để có được danh sách bạn bè của người dùng, yêu cầu phải được gửi qua mạng, quá trình này có thể mất nhiều thời gian. Điều này được minh họa bằng lệnh gọi phương thức 04 trả về 05. Để sử dụng CPU tốt hơn cho đến khi có phản hồi, chúng ta không nên chặn phần còn lại của chương trình – quá trình tính toán này phải được lên lịch không đồng bộ. Phương thức 8 thực hiện chính xác điều đó– nó thực hiện đồng thời khối tính toán đã chỉ định, trong trường hợp này là gửi yêu cầu đến máy chủ và chờ phản hồiDanh sách bạn bè sẽ có trong tương lai 07 sau khi máy chủ phản hồiMột nỗ lực không thành công có thể dẫn đến một ngoại lệ. Trong ví dụ sau, giá trị 08 được khởi tạo không chính xác, vì vậy phép tính trong khối 2 sẽ tạo ra một giá trị 10. 07 trong tương lai này sau đó không thành công với ngoại lệ này thay vì được hoàn thành thành công
Dòng 12 ở trên nhập ngữ cảnh thực thi chung mặc định. Bối cảnh thực thi thực thi các tác vụ được gửi cho chúng và bạn có thể coi bối cảnh thực thi là nhóm luồng. Chúng rất cần thiết cho phương pháp 8 vì chúng xử lý cách thức và thời điểm thực hiện tính toán không đồng bộ. Bạn có thể xác định bối cảnh thực thi của riêng mình và sử dụng chúng với 2, nhưng hiện tại bạn chỉ cần biết rằng bạn có thể nhập bối cảnh thực thi mặc định như minh họa ở trên là đủVí dụ của chúng tôi dựa trên API mạng xã hội giả định trong đó quá trình tính toán bao gồm gửi yêu cầu mạng và chờ phản hồi. Thật công bằng khi đưa ra một ví dụ liên quan đến tính toán không đồng bộ mà bạn có thể thử ngay lập tức. Giả sử bạn có một tệp văn bản và bạn muốn tìm vị trí xuất hiện đầu tiên của một từ khóa cụ thể. Tính toán này có thể liên quan đến việc chặn trong khi nội dung tệp đang được truy xuất từ đĩa, vì vậy sẽ hợp lý khi thực hiện nó đồng thời với phần còn lại của tính toán
gọi lạiBây giờ chúng tôi biết cách bắt đầu tính toán không đồng bộ để tạo ra một giá trị mới trong tương lai, nhưng chúng tôi chưa chỉ ra cách sử dụng kết quả khi nó có sẵn, để chúng tôi có thể làm điều gì đó hữu ích với nó. Chúng ta thường quan tâm đến kết quả tính toán, không chỉ các tác dụng phụ của nó Trong nhiều triển khai trong tương lai, một khi khách hàng của tương lai quan tâm đến kết quả của nó, nó phải chặn tính toán của chính nó và đợi cho đến khi tương lai hoàn thành– chỉ khi đó, nó mới có thể sử dụng giá trị của tương lai để tiếp tục tính toán của chính mình. Mặc dù điều này được cho phép bởi API Scala 2 như chúng tôi sẽ trình bày sau, nhưng từ quan điểm hiệu suất, cách tốt hơn để làm điều đó là theo cách hoàn toàn không bị chặn, bằng cách đăng ký gọi lại trong tương lai. Cuộc gọi lại này được gọi không đồng bộ sau khi hoàn thành tương lai. Nếu tương lai đã được hoàn thành khi đăng ký cuộc gọi lại, thì cuộc gọi lại có thể được thực hiện không đồng bộ hoặc tuần tự trên cùng một luồngHình thức đăng ký gọi lại chung nhất là sử dụng phương thức 16, phương thức này nhận hàm gọi lại kiểu 17. Cuộc gọi lại được áp dụng cho giá trị của loại 18 nếu tương lai hoàn thành thành công hoặc cho giá trị của loại 19 nếu không 20 tương tự như 21 hoặc 22, ở chỗ nó là một đơn nguyên có khả năng nắm giữ một loại giá trị nào đó. Tuy nhiên, nó đã được thiết kế đặc biệt để giữ một giá trị hoặc một số đối tượng có thể ném được. Trường hợp một 21 có thể là một giá trị (i. e. 24) hoặc không có giá trị gì cả (i. e. 25), 20 là một 18 khi nó giữ một giá trị và nếu không thì 19, giữ một ngoại lệ. 19 nắm giữ nhiều thông tin hơn là chỉ một 25 đơn giản bằng cách cho biết tại sao giá trị không có ở đó. Đồng thời, bạn có thể coi 20 là phiên bản đặc biệt của 32, chuyên dùng cho trường hợp giá trị bên trái là 33Quay lại ví dụ về mạng xã hội của chúng tôi, giả sử chúng tôi muốn tìm nạp danh sách các bài đăng gần đây của chính mình và hiển thị chúng trên màn hình. Chúng tôi làm như vậy bằng cách gọi một phương thức 34 trả về một 35– một danh sách các bài viết văn bản gần đây
7Phương pháp 16 nói chung theo nghĩa là nó cho phép khách hàng xử lý kết quả của cả các phép tính thất bại và thành công trong tương lai. Trong trường hợp chỉ cần xử lý kết quả thành công, có thể sử dụng lệnh gọi lại 4
9 2s cung cấp một cách rõ ràng để chỉ xử lý các kết quả không thành công bằng cách sử dụng phép chiếu 39 để chuyển đổi một 40 thành một 41. Một ví dụ về cách làm này được cung cấp trong phần bên dưới vềQuay lại ví dụ trước với việc tìm kiếm lần xuất hiện đầu tiên của từ khóa, bạn có thể muốn in vị trí của từ khóa ra màn hình
Cả hai phương thức 16 và 4 đều có loại kết quả là 44, có nghĩa là các lệnh gọi của các phương thức này không thể được xâu chuỗi. Lưu ý rằng thiết kế này là có chủ ý, để tránh gợi ý rằng các lệnh gọi theo chuỗi có thể ngụ ý một thứ tự khi thực hiện các lệnh gọi lại đã đăng ký (các lệnh gọi lại đã đăng ký trong cùng một tương lai là không có thứ tự)Điều đó nói rằng, bây giờ chúng ta nên bình luận về thời điểm gọi lại chính xác. Vì nó yêu cầu giá trị trong tương lai phải có sẵn, nên nó chỉ có thể được gọi sau khi tương lai hoàn thành. Tuy nhiên, không có gì đảm bảo rằng nó sẽ được gọi bởi chuỗi đã hoàn thành tương lai hoặc chuỗi đã tạo cuộc gọi lại. Thay vào đó, cuộc gọi lại được thực hiện bởi một số luồng, tại một số thời điểm sau khi hoàn thành đối tượng tương lai. Chúng tôi nói rằng cuộc gọi lại được thực hiện cuối cùng Hơn nữa, thứ tự thực hiện các cuộc gọi lại không được xác định trước, ngay cả giữa các lần chạy khác nhau của cùng một ứng dụng. Trên thực tế, các callback có thể không được gọi tuần tự lần lượt mà có thể thực thi đồng thời cùng một lúc. Điều này có nghĩa là trong ví dụ sau, biến 45 có thể không được đặt thành đúng số lượng chữ thường và chữ hoa 46 ký tự từ văn bản được tính toán
Ở trên, hai cuộc gọi lại có thể thực hiện lần lượt từng cuộc gọi, trong trường hợp đó, biến 45 giữ giá trị mong đợi 48. Tuy nhiên, chúng cũng có thể thực hiện đồng thời, do đó, 45 có thể kết thúc bằng hoặc là 50 hoặc 51, vì 52 không phải là phép toán nguyên tử (i. e. nó bao gồm một bước đọc và ghi có thể xen kẽ tùy ý với các lần đọc và ghi khác)Để hoàn thiện, ngữ nghĩa của các cuộc gọi lại được liệt kê ở đây
Thành phần chức năng và khả năng hiểuCơ chế gọi lại mà chúng tôi đã chỉ ra là đủ để xâu chuỗi các kết quả trong tương lai với các tính toán tiếp theo. Tuy nhiên, nó đôi khi bất tiện và dẫn đến mã cồng kềnh. Chúng tôi hiển thị điều này với một ví dụ. Giả sử chúng tôi có API để giao tiếp với dịch vụ giao dịch tiền tệ. Giả sử chúng ta muốn mua đô la Mỹ, nhưng chỉ khi nó sinh lãi. Trước tiên, chúng tôi chỉ ra cách điều này có thể được thực hiện bằng cách sử dụng lệnh gọi lại
3Chúng tôi bắt đầu bằng cách tạo một 58 tương lai có tỷ giá hối đoái hiện tại. Sau khi giá trị này được lấy từ máy chủ và tương lai hoàn tất thành công, quá trình tính toán sẽ tiếp tục trong cuộc gọi lại 4 và chúng tôi sẵn sàng quyết định có mua hay không. Do đó, chúng tôi tạo ra một 60 tương lai khác sẽ đưa ra quyết định mua chỉ khi làm như vậy có lợi, sau đó gửi yêu cầu. Cuối cùng, khi quá trình mua hàng hoàn tất, chúng tôi sẽ in thông báo thông báo ra đầu ra tiêu chuẩnĐiều này hoạt động, nhưng bất tiện vì hai lý do. Đầu tiên, chúng ta phải sử dụng 4 và lồng tương lai thứ hai của 60 vào bên trong nó. Hãy tưởng tượng rằng sau khi hoàn thành 60, chúng tôi muốn bán một số loại tiền tệ khác. Chúng tôi sẽ phải lặp lại mô hình này trong cuộc gọi lại 4, khiến mã bị thụt vào quá mức, cồng kềnh và khó lý giảiThứ hai, tương lai 60 không nằm trong phạm vi của phần còn lại của mã– nó chỉ có thể được thực hiện từ bên trong cuộc gọi lại 4. Điều này có nghĩa là các phần khác của ứng dụng không nhìn thấy tương lai 60 và không thể đăng ký một cuộc gọi lại 4 khác cho nó, ví dụ: để bán một số loại tiền tệ khácVì hai lý do này, hợp đồng tương lai cung cấp các bộ kết hợp cho phép bố cục đơn giản hơn. Một trong những tổ hợp cơ bản là 69, được cung cấp một tương lai và chức năng ánh xạ cho giá trị của tương lai, tạo ra một tương lai mới được hoàn thành với giá trị được ánh xạ sau khi tương lai ban đầu được hoàn thành thành công. Bạn có thể lập luận về việc lập bản đồ tương lai giống như cách bạn lập luận về việc lập bản đồ các bộ sưu tậpHãy viết lại ví dụ trước bằng cách sử dụng bộ kết hợp 69
5Bằng cách sử dụng 69 trên 58, chúng tôi đã loại bỏ một cuộc gọi lại 4 và quan trọng hơn là lồng nhau. Nếu bây giờ chúng tôi quyết định bán một số loại tiền tệ khác, thì chỉ cần sử dụng lại 69 trên 60 là đủNhưng điều gì sẽ xảy ra nếu 76 trả về 77, do đó gây ra một ngoại lệ bị ném? . Hơn nữa, hãy tưởng tượng rằng kết nối bị hỏng và 79 đã ném một ngoại lệ, không thành công 58. Trong trường hợp đó, chúng tôi sẽ không có giá trị để lập bản đồ, do đó, 60 sẽ tự động bị lỗi với cùng một ngoại lệ như 58Tóm lại, nếu tương lai ban đầu được hoàn thành thành công thì tương lai được trả về sẽ được hoàn thành với giá trị được ánh xạ từ tương lai ban đầu. Nếu chức năng lập bản đồ đưa ra một ngoại lệ thì tương lai sẽ hoàn thành với ngoại lệ đó. Nếu tương lai ban đầu không thành công với một ngoại lệ thì tương lai được trả về cũng chứa ngoại lệ tương tự. Ngữ nghĩa lan truyền ngoại lệ này cũng có mặt trong phần còn lại của các bộ tổ hợp. Một trong những mục tiêu thiết kế cho tương lai là cho phép sử dụng chúng để hiểu. Vì lý do này, hợp đồng tương lai cũng có các tổ hợp 3 và 84. Phương thức 3 nhận một hàm ánh xạ giá trị tới một tương lai mới 86, sau đó trả về một tương lai được hoàn thành sau khi hoàn thành 86Giả sử rằng chúng ta muốn đổi đô la Mỹ lấy đồng franc Thụy Sĩ (CHF). Chúng tôi phải lấy báo giá cho cả hai loại tiền tệ và sau đó quyết định mua dựa trên cả hai báo giá. Dưới đây là một ví dụ về cách sử dụng 3 và 84 trong phạm vi hiểu
7Tương lai 60 chỉ được hoàn thành khi cả hai 91 và 92 được hoàn thành– nó phụ thuộc vào giá trị của cả hai tương lai này nên quá trình tính toán của chính nó không thể bắt đầu sớm hơnphần dễ hiểu ở trên được dịch sang
khó nắm bắt hơn một chút so với phần dễ hiểu, nhưng chúng tôi phân tích nó để hiểu rõ hơn về hoạt động 3. Hoạt động 3 ánh xạ giá trị của chính nó vào một số tương lai khác. Khi tương lai khác này được hoàn thành, tương lai kết quả được hoàn thành với giá trị của nó. Trong ví dụ của chúng tôi, 3 sử dụng giá trị của tương lai 91 để ánh xạ giá trị của 92 vào tương lai thứ ba gửi yêu cầu mua một lượng franc Thụy Sĩ nhất định. Tương lai kết quả 60 chỉ được hoàn thành khi tương lai thứ ba này được trả về từ 69 hoàn thànhĐiều này có thể gây khó hiểu, nhưng may mắn thay, phép toán 3 hiếm khi được sử dụng bên ngoài để hiểu, dễ sử dụng và dễ hiểu hơnBộ kết hợp 5 tạo ra một tương lai mới chỉ chứa giá trị của tương lai ban đầu nếu nó thỏa mãn một số vị từ. Mặt khác, tương lai mới không thành công với một 02. Đối với các hợp đồng tương lai gọi 5 có tác dụng chính xác giống như việc gọi 84Mối quan hệ giữa bộ kết hợp 05 và 5 tương tự như mối quan hệ của các phương thức này trong API bộ sưu tậpVì đặc điểm 2 về mặt khái niệm có thể chứa hai loại giá trị (kết quả tính toán và ngoại lệ), nên cần có bộ kết hợp xử lý ngoại lệGiả sử rằng dựa trên 58, chúng tôi quyết định mua một số lượng nhất định. Phương pháp 09 cần một 10 để mua và dự kiến là 11. Nó trả về số tiền đã mua. Nếu 11 đã thay đổi trong khi đó, nó sẽ ném một 13 và nó sẽ không mua bất cứ thứ gì. Nếu chúng tôi muốn tương lai của chúng tôi chứa 14 thay vì ngoại lệ, chúng tôi sử dụng bộ kết hợp 15
Bộ kết hợp 15 tạo ra một tương lai mới có cùng kết quả với tương lai ban đầu nếu nó hoàn thành thành công. Nếu không thì đối số hàm một phần được áp dụng cho 33 không thành công trong tương lai ban đầu. Nếu nó ánh xạ 33 tới một giá trị nào đó, thì tương lai mới sẽ được hoàn thành thành công với giá trị đó. Nếu chức năng một phần không được xác định trên 33 đó, thì tương lai kết quả sẽ thất bại với cùng một 33Bộ kết hợp 21 tạo ra một tương lai mới có cùng kết quả với tương lai ban đầu nếu nó hoàn thành thành công. Mặt khác, chức năng một phần được áp dụng cho 33 không thành công trong tương lai ban đầu. Nếu nó ánh xạ 33 tới một tương lai nào đó, thì tương lai này được hoàn thành với kết quả của tương lai đó. Mối quan hệ của nó với 15 tương tự như mối quan hệ của 3 với 69Bộ kết hợp 27 tạo ra một tương lai mới chứa kết quả của tương lai này nếu nó được hoàn thành thành công hoặc nếu không thì kết quả thành công của đối số tương lai. Trong trường hợp cả tương lai này và tương lai đối số đều không thành công, thì tương lai mới được hoàn thành ngoại trừ tương lai này, như trong ví dụ sau cố gắng in giá trị đô la Mỹ, nhưng in giá trị đồng franc Thụy Sĩ trong trường hợp nó không thành công
Bộ kết hợp 28 được sử dụng hoàn toàn cho các mục đích tác dụng phụ. Nó trả về một tương lai mới với kết quả chính xác như tương lai hiện tại, bất kể tương lai hiện tại có thất bại hay không. Khi thì tương lai hiện tại được hoàn thành với kết quả, thì lần đóng tương ứng với 28 được gọi và sau đó thì tương lai mới được hoàn thành với kết quả tương tự như tương lai này. Điều này đảm bảo rằng nhiều cuộc gọi 28 được sắp xếp, như trong ví dụ sau lưu trữ các bài đăng gần đây từ mạng xã hội vào một tập hợp có thể thay đổi và sau đó hiển thị tất cả các bài đăng lên màn hình
2Tóm lại, các tổ hợp trên tương lai hoàn toàn là chức năng. Mỗi tổ hợp trả về một tương lai mới có liên quan đến tương lai mà nó được bắt nguồn từ dự đoánĐể kích hoạt tính năng dễ hiểu đối với kết quả được trả về dưới dạng ngoại lệ, hợp đồng tương lai cũng có các dự báo. Nếu tương lai ban đầu không thành công, phép chiếu 39 trả về một tương lai chứa giá trị loại 33. Nếu tương lai ban đầu thành công, phép chiếu 39 thất bại với một 02. Sau đây là một ví dụ in ngoại lệ ra màn hình
4for-hiểu trong ví dụ này được dịch sang 5Bởi vì 07 không thành công ở đây, việc đóng cửa được đăng ký cho cuộc gọi lại 4 trên một 37 mới thành công. Ví dụ sau không in gì ra màn hình
7Mở rộng tương laiHỗ trợ mở rộng API tương lai với các phương thức tiện ích bổ sung đã được lên kế hoạch. Điều này sẽ cho phép các khung bên ngoài cung cấp các tiện ích chuyên biệt hơn chặnHợp đồng tương lai nói chung là không đồng bộ và không chặn các luồng thực thi cơ bản. Tuy nhiên, trong một số trường hợp nhất định, cần phải chặn. Chúng tôi phân biệt hai hình thức chặn luồng thực thi. gọi mã tùy ý chặn luồng từ bên trong tương lai và chặn từ bên ngoài một tương lai khác, đợi cho đến khi tương lai đó hoàn thành Chặn bên trong một tương laiNhư đã thấy với 7 toàn cầu, có thể thông báo cho một 7 về một cuộc gọi chặn với cấu trúc 9. Tuy nhiên, việc thực hiện hoàn toàn theo quyết định của 7. Trong khi một số 7 chẳng hạn như 6 triển khai 9 bằng phương tiện của một 45, thì một số ngữ cảnh thực thi chẳng hạn như nhóm luồng cố định
sẽ không làm gì cả, như thể hiện trong hình dưới đây
0Có tác dụng tương tự như
Mã chặn cũng có thể đưa ra một ngoại lệ. Trong trường hợp này, ngoại lệ được chuyển tiếp đến người gọi Chặn bên ngoài Tương laiNhư đã đề cập trước đó, việc ngăn chặn một tương lai không được khuyến khích vì lợi ích của hiệu suất và để ngăn chặn bế tắc. Gọi lại và tổ hợp trên tương lai là một cách ưa thích để sử dụng kết quả của họ. Tuy nhiên, việc chặn có thể cần thiết trong một số trường hợp nhất định và được hỗ trợ bởi API Futures and Promises Trong ví dụ giao dịch tiền tệ ở trên, một nơi để chặn nằm ở cuối ứng dụng để đảm bảo rằng tất cả các hợp đồng tương lai đã được hoàn thành. Dưới đây là một ví dụ về cách chặn kết quả của một tương lai
3Trong trường hợp tương lai không thành công, người gọi được chuyển tiếp ngoại lệ mà tương lai không thành công. Điều này bao gồm phép chiếu 39– việc chặn nó dẫn đến việc ném ra một 02 nếu tương lai ban đầu được hoàn thành thành côngNgoài ra, gọi 48 đợi cho đến khi tương lai hoàn thành, nhưng không truy xuất kết quả của nó. Theo cách tương tự, gọi phương thức đó sẽ không ném ngoại lệ nếu tương lai không thành côngĐặc điểm 2 thực hiện đặc điểm 50 với các phương pháp 51 và 52. Các phương thức này không thể được gọi trực tiếp bởi máy khách– chúng chỉ có thể được gọi bởi bối cảnh thực thingoại lệKhi tính toán không đồng bộ đưa ra các ngoại lệ chưa được xử lý, tương lai liên quan đến các tính toán đó sẽ không thành công. Hợp đồng tương lai không thành công lưu trữ một thể hiện của 33 thay vì giá trị kết quả. Các 2 cung cấp phương pháp chiếu 39, cho phép 33 này được coi là giá trị thành công của một 2 khác. Các trường hợp ngoại lệ đặc biệt sau đây được đối xử khác nhau
Các ngoại lệ nghiêm trọng (như được xác định bởi 66) được viết lại trong chuỗi thực thi tính toán không đồng bộ không thành công. Điều này thông báo cho mã quản lý các luồng thực thi của sự cố và cho phép nó bị lỗi nhanh, nếu cần. Xem 66 để biết mô tả chính xác hơn về ngữ nghĩaCho đến nay, chúng tôi chỉ xem xét các đối tượng 2 được tạo bởi các tính toán không đồng bộ bắt đầu bằng phương pháp 2. Tuy nhiên, tương lai cũng có thể được tạo bằng lời hứaMặc dù tương lai được định nghĩa là một loại đối tượng giữ chỗ chỉ đọc được tạo cho một kết quả chưa tồn tại, nhưng một lời hứa có thể được coi là một vùng chứa chỉ định một lần, có thể ghi, hoàn thành một tương lai. Nghĩa là, một lời hứa có thể được sử dụng để hoàn thành thành công một tương lai có giá trị (bằng cách “hoàn thành” lời hứa) bằng cách sử dụng phương thức 70. Ngược lại, một lời hứa cũng có thể được sử dụng để hoàn thành một tương lai với một ngoại lệ, bằng cách thất hứa, sử dụng phương thức 71Một lời hứa 72 hoàn thành tương lai được trả lại bởi 73. Tương lai này là cụ thể cho lời hứa 72. Tùy thuộc vào việc triển khai, có thể xảy ra trường hợp 75Xem xét ví dụ về người sản xuất-người tiêu dùng sau đây, trong đó một phép tính tạo ra một giá trị và chuyển nó cho một phép tính khác tiêu thụ giá trị đó. Việc chuyển giá trị này được thực hiện bằng một lời hứa
Ở đây, chúng tôi tạo một lời hứa và sử dụng phương pháp 76 của nó để có được 2 mà nó hoàn thành. Sau đó, chúng tôi bắt đầu hai tính toán không đồng bộ. Cái đầu tiên thực hiện một số tính toán, dẫn đến giá trị 78, sau đó được sử dụng để hoàn thành tương lai 07, bằng cách thực hiện lời hứa 72. Người thứ hai thực hiện một số tính toán, sau đó đọc kết quả 78 của thì tương lai hoàn thành 07. Lưu ý rằng 83 có thể nhận được kết quả trước khi tác vụ 84 hoàn thành việc thực thi phương thức 85Như đã đề cập trước đây, các lời hứa có ngữ nghĩa chỉ định một lần. Như vậy, chúng có thể được hoàn thành chỉ một lần. Gọi 70 trên một lời hứa đã được hoàn thành (hoặc không thành công) sẽ tạo ra một 87Ví dụ sau đây cho thấy cách thất bại trong một lời hứa
6Ở đây, 84 tính toán kết quả trung gian 78 và kiểm tra xem nó có hợp lệ không. Trong trường hợp nó không hợp lệ, nó sẽ thất bại trong lời hứa bằng cách hoàn thành lời hứa 72 với một ngoại lệ. Trong trường hợp này, tương lai liên quan 07 không thành công. Mặt khác, 84 tiếp tục tính toán của nó, và cuối cùng hoàn thành tương lai 07 với một kết quả hợp lệ, bằng cách hoàn thành lời hứa 72Lời hứa cũng có thể được hoàn thành bằng phương pháp 95 có giá trị tiềm năng 20– kết quả thất bại thuộc loại 40 hoặc kết quả thành công thuộc loại 18Tương tự như 70, gọi 71 và 95 trên một lời hứa đã được hoàn thành sẽ đưa ra một 87Một đặc tính hay của các chương trình được viết bằng lời hứa với các hoạt động được mô tả cho đến nay và tương lai được tạo thành thông qua các hoạt động đơn nguyên mà không có tác dụng phụ là các chương trình này có tính xác định. Tất định ở đây có nghĩa là, với điều kiện là không có ngoại lệ nào được đưa vào chương trình, kết quả của chương trình (các giá trị được quan sát trong tương lai) sẽ luôn giống nhau, bất kể lịch trình thực hiện của chương trình song song Trong một số trường hợp, khách hàng có thể chỉ muốn hoàn thành lời hứa nếu nó chưa được hoàn thành (e. g. , có một số yêu cầu HTTP đang được thực hiện từ một số tương lai khác nhau và khách hàng chỉ quan tâm đến phản hồi HTTP đầu tiên - tương ứng với tương lai đầu tiên để hoàn thành lời hứa). Vì những lý do này, các phương pháp 03, 04 và 05 tồn tại theo lời hứa. Khách hàng nên lưu ý rằng việc sử dụng các phương pháp này dẫn đến các chương trình không mang tính quyết định mà phụ thuộc vào lịch trình thực hiệnPhương pháp 06 hoàn thành lời hứa với một tương lai khác. Sau khi tương lai được hoàn thành, lời hứa cũng được hoàn thành với kết quả của tương lai đó. Chương trình sau in ra 07
Khi thất hứa với một ngoại lệ, ba loại phụ của 33 được xử lý đặc biệt. Nếu 33 được sử dụng để thất hứa là một 10, thì lời hứa được hoàn thành với giá trị tương ứng. Nếu 33 được sử dụng để phá vỡ lời hứa là một trường hợp của 63, 62 hoặc 64, thì 33 được bao bọc như là nguyên nhân của một ________6__61 mới, đến lượt nó lại thất hứaSử dụng lời hứa, phương pháp 16 của tương lai và cấu trúc 76, bạn có thể triển khai bất kỳ tổ hợp thành phần chức năng nào được mô tả trước đó. Giả sử bạn muốn triển khai một bộ kết hợp mới 19, lấy hai hợp đồng tương lai 07 và 86 và tạo ra một hợp đồng tương lai thứ ba được hoàn thành bởi 07 hoặc 86 (tùy theo điều kiện nào đến trước), nhưng chỉ với điều kiện là nó thành côngĐây là một ví dụ về cách thực hiện
9Lưu ý rằng trong triển khai này, nếu cả 07 và 86 đều không thành công, thì 26 sẽ không bao giờ hoàn thành (có giá trị hoặc có ngoại lệ)tiện íchĐể đơn giản hóa việc xử lý thời gian trong các ứng dụng đồng thời 1 giới thiệu một sự trừu tượng hóa 28. 28 không được coi là một sự trừu tượng hóa thời gian chung khác. Nó được dùng với các thư viện đồng thời và nằm trong gói 1 28 là lớp cơ sở đại diện cho một khoảng thời gian. Nó có thể là hữu hạn hoặc vô hạn. Khoảng thời gian hữu hạn được biểu diễn bằng lớp 32, được xây dựng từ độ dài 33 và lớp 34. Thời hạn vô hạn, cũng kéo dài từ 28, chỉ tồn tại trong hai trường hợp, 36 và 37. Thư viện cũng cung cấp một số lớp con 28 cho các mục đích chuyển đổi ngầm định và những lớp con này không nên được sử dụngTóm tắt 28 chứa các phương thức cho phép
28 có thể được khởi tạo theo các cách sau
Thời lượng cũng cung cấp các phương thức 69, vì vậy nó có thể được sử dụng trong các cấu trúc đối sánh mẫu. ví dụ
Sự khác biệt giữa tương lai và lời hứa trong JavaScript là gì?Cụ thể, khi cách sử dụng được phân biệt, một tương lai là dạng xem giữ chỗ chỉ đọc của một biến, trong khi một lời hứa là một vùng chứa gán đơn, có thể ghi, đặt giá trị của tương lai
Sự khác biệt giữa Tương lai và một lời hứa là gì?Tương lai và lời hứa là những khái niệm khá giống nhau, điểm khác biệt là tương lai là vùng chứa chỉ đọc cho kết quả chưa tồn tại, trong khi lời hứa có thể được viết ( . .
Sự khác biệt giữa lời hứa Rust Future và JavaScript là gì?Hợp đồng tương lai trong Rust không minh bạch như Hứa hẹn trong JavaScript . Đó là vì những gì mỗi ngôn ngữ đang cố gắng làm. JavaScript là ngôn ngữ cấp cao bao gồm vòng lặp thời gian chạy và sự kiện xử lý việc lên lịch tác vụ không đồng bộ và chạy lệnh gọi lại, khiến nhà phát triển ứng dụng chỉ sử dụng các tính năng này.
Những lời hứa vẫn được sử dụng trong JavaScript?Lời hứa được sử dụng để xử lý các hoạt động không đồng bộ trong JavaScript. Chúng rất dễ quản lý khi xử lý nhiều hoạt động không đồng bộ trong đó các lệnh gọi lại có thể tạo ra địa ngục gọi lại dẫn đến mã không thể quản lý được. |