2 điểm bởi GN⁺ 2025-01-31 | 1 bình luận | Chia sẻ qua WhatsApp
  • Đối tượng Temporal mới của JavaScript bắt đầu xuất hiện trong các bản phát hành thử nghiệm của trình duyệt; đây là thay đổi nhằm xử lý ngày, giờ, khoảng thời gian và lịch chính xác, nhất quán hơn bằng API tích hợp sẵn
  • Date hiện tại khiến xử lý múi giờ và gỡ lỗi trở nên khó khăn do cấu trúc xoay quanh giờ cục bộ của người dùng và UTC, cơ chế phân tích cú pháp không ổn định, cùng hành vi mutable
  • Temporal tách bạch thời điểm, giờ địa phương và khoảng thời gian bằng các kiểu như Temporal.Instant, Temporal.ZonedDateTime, Temporal.PlainDateTime, Temporal.Duration, Temporal.Now, đồng thời cung cấp hơn 200 phương thức tiện ích
  • Vẫn cần thêm thời gian để có hỗ trợ ổn định trên nhiều trình duyệt; trên Firefox Nightly có thể thử Temporal sau thiết lập javascript.options.experimental.temporal
  • Tuần này MDN đã bổ sung hơn 270 trang tài liệu Temporal, và có thể chạy ví dụ mà không cần đổi flag trên trang tài liệu TC39 có @js-temporal/polyfill

Những hạn chế lâu đời của JavaScript Date

  • Khi JavaScript được tạo ra vào năm 1995, đối tượng Date đã sao chép triển khai java.util.Date ban đầu của Java; Java đã thay thế nó vào năm 1997, nhưng JavaScript vẫn duy trì gần như cùng một API trong gần 30 năm
  • Vấn đề lớn nhất là thiếu hỗ trợ múi giờ và hành vi phân tích cú pháp không ổn định
    • Chỉ hỗ trợ giờ cục bộ của người dùng và UTC
    • Bản thân Date là mutable nên có thể tạo ra các lỗi khó theo dõi
    • Các phép tính đi qua Daylight Saving Time (DST) và những thay đổi lịch sử của lịch cũng khó xử lý
  • Vì những hạn chế này, nhiều nhà phát triển đã dựa vào các thư viện chuyên dụng như Moment.js hoặc date-fns để xử lý ngày và giờ trong ứng dụng

Temporal thay đổi mô hình ngày giờ như thế nào

  • Temporal được thiết kế như một sự thay thế toàn diện cho đối tượng Date, với mục tiêu giúp quản lý ngày giờ đáng tin cậy và dễ dự đoán hơn
  • Hỗ trợ biểu diễn múi giờ và lịch, đồng thời cung cấp các phương thức tích hợp sẵn để chuyển đổi, so sánh, tính toán và định dạng
  • Bề mặt API có hơn 200 phương thức tiện ích, và MDN đã bổ sung phần giải thích cùng ví dụ trong tài liệu Temporal

Các kiểu chính của Temporal

  • Temporal phân biệt một thời điểm duy nhất, giờ đồng hồ treo tường tại địa phương và khoảng thời gian thành các kiểu khác nhau
  • Các cấu trúc chính như sau
    • Temporal.Duration: chênh lệch giữa hai thời điểm
    • Temporal.Instant: một thời điểm duy nhất được biểu diễn bằng timestamp
    • Temporal.ZonedDateTime: ngày giờ có kèm múi giờ
    • Temporal.PlainDateTime: ngày giờ đầy đủ không có múi giờ
      • Temporal.PlainDate: chỉ biểu diễn ngày
      • Temporal.PlainYearMonth: năm và tháng
      • Temporal.PlainMonthDay: tháng và ngày
      • Temporal.PlainTime: chỉ biểu diễn giờ
    • Temporal.Now: API để lấy thời gian hiện tại dưới dạng instance của nhiều lớp hoặc theo định dạng cụ thể

Cách dùng qua ví dụ

  • Có thể lấy ngày giờ hiện tại dưới dạng chuỗi ISO và truyền múi giờ vào nhiều phương thức
    • Temporal.Now.plainDateTimeISO() trả về ngày giờ hiện tại theo múi giờ hệ thống
    • Temporal.Now.plainDateTimeISO("America/New_York") trả về ngày giờ hiện tại theo múi giờ New York
  • Cũng có thể xử lý các lịch ngoài Gregorian, cho phép tạo ngày trong các hệ lịch như Hebrew, Chinese, Islamic
    • Tính Chinese New Year tiếp theo bằng ngày 1 của M01 trong lịch Chinese
    • Trong kết quả ví dụ tại thời điểm viết bài, Chinese New Year tiếp theo là 1/29/2025
  • Có thể tạo một thời điểm từ timestamp mili giây Unix Epoch bằng Temporal.Instant.fromEpochMilliseconds(), rồi so sánh với Temporal.Now.instant() để tính thời gian còn lại
    • Với timestamp ví dụ 1851222399924, tính thời gian từ hiện tại bằng smallestUnit: "hour"
    • Kết quả từ @js-temporal/polyfill31,600 hr, còn kết quả từ Firefox Nightly là PT31600H
  • toLocaleString trong triển khai Firefox hiện không xuất ra chuỗi nhạy theo locale
    • Hành vi này gần với một quyết định thiết kế hơn là giới hạn kỹ thuật, và bản thân việc định dạng duration vẫn khả thi
    • Polyfill và triển khai Firefox có thể hội tụ về sau
  • Phương thức compare() có thể dùng để sắp xếp mảng
    • Dùng durations.sort(Temporal.Duration.compare) sẽ sắp xếp theo thứ tự PT1H, PT1H30M, PT1H45M, PT2H

Hỗ trợ trình duyệt và cách thử nghiệm

1 bình luận

 
GN⁺ 2025-01-31
Ý kiến trên Hacker News
  • Temporal rất tuyệt. Tôi đã dùng nó trong production một thời gian bằng polyfill, và nó giải quyết được rất nhiều vấn đề tôi từng gặp với API Date()
    Cảm giác như nó lấy cảm hứng từ các thư viện thời gian tốt như chrono của Rust hay Joda Time của Java rồi kết hợp lại thành một API dễ dùng
    Nó tách riêng thời gian đơn thuần, thời điểm, và thời gian có kèm múi giờ nên có phần phức tạp hơn, nhưng bản thân thời gian vốn đã phức tạp, nên lập trình viên cần đối diện với sự phức tạp đó
    Với những thao tác như “cộng thêm một ngày vào timestamp này”, bạn cũng buộc phải quyết định là theo múi giờ nào; nếu không thì sẽ sinh lỗi do giờ tiết kiệm ánh sáng ban ngày, do người dùng đổi múi giờ, hoặc do chênh lệch múi giờ của máy chủ
    Nó cũng xử lý được sự khác biệt khi tuần tự hóa giữa timestamp có offset cố định (2025-01-01T00:00+02:00) và timestamp theo một múi giờ cụ thể (Europe/Paris)

    • Crate Rust Jiff cũng đáng xem. Nó lấy cảm hứng từ Temporal, đồng thời có tổng hợp so sánh với các crate ngày giờ khác bao gồm chrono: https://docs.rs/jiff/latest/jiff/_documentation/comparison/i...
      Cá nhân tôi không nghĩ Temporal chịu ảnh hưởng quá nhiều từ chrono của Rust; có vẻ nó bị ảnh hưởng nhiều hơn từ Joda, java.time hiện đại, và các thư viện ngày giờ JavaScript như date-fns hay Moment.js
    • Những người có chút tuổi nghề đều đã học từ lâu rằng trong môi trường production, đừng lên lịch cron job vào khoảng 01:00~03:00 theo giờ địa phương
    • Đúng là vậy, nhưng có một trở ngại. Nhiều người thực sự ghét dùng tên múi giờ chỉ vị trí thực tế
      Họ không muốn đi tra xem Europe/Paris là chỉ cả một vùng rộng của Pháp hay chỉ riêng Paris, và còn thấy khó chịu vì có cảm giác như đang nói rằng mình sống ở Paris
      Điều này từng rất đau đầu khi lên lịch cho các sự kiện cộng đồng trực tuyến. Mọi người muốn dùng offset cố định, và chấp nhận các cách viết như CET/CEST, nhưng lại không thích kiểu Europe/yourexactcoordinates
      Thực ra hầu hết múi giờ đều bao phủ khu vực khá rộng, nhưng có rất nhiều người vừa quan tâm đến quyền riêng tư lại vừa không định tìm hiểu sự khác biệt giữa “thời gian” và “múi giờ”
    • chrono và Joda Time là sản phẩm của hai thời đại khác nhau. Khi Rust 1.0 ra mắt thì Java đã triển khai cách tiếp cận này trong java.time của thư viện chuẩn, và không cần thư viện bên thứ ba cho mục đích này nữa
    • Tôi muốn hiểu rõ hơn sự khác biệt khi tuần tự hóa giữa timestamp offset cố định và timestamp theo múi giờ cụ thể gây ra vấn đề gì
  • Tôi mất khá nhiều thời gian mới tìm được trong tài liệu rằng Temporal.ZonedDateTime.prototype.withTimeZone() dùng để chuyển đổi từ múi giờ này sang múi giờ khác: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
    Nếu tạo giá trị bằng Temporal.ZonedDateTime.from("2021-08-01T12:00[America/New_York]") rồi truyền vào withTimeZone("Europe/Paris"), thì sẽ nhận được 2021-08-01T18:00:00+02:00[Europe/Paris]
    Chuyển đổi múi giờ và xử lý khoảng thời gian là các tính năng cốt lõi mà thư viện bắt buộc phải xử lý, nên thật tốt khi Temporal làm được cả hai. Tuy vậy, có vẻ Temporal.Duration không có hàm format tùy biến để tạo ra dạng như 1h03m, chẳng hạn duration.format('H\hmm\m')

  • Hiện TC39 có khá nhiều đề xuất đang dần chín muồi, và Temporal là một trong những thứ mình rất muốn được phát hành sớm
    Mình hiểu rằng để các trình duyệt lớn hỗ trợ tính năng mới thì cần nỗ lực phát triển từ các kỹ sư của v8, JSC và SpiderMonkey, nên thật sự rất biết ơn những người đang tạo ra tiến triển này
    Từ góc nhìn sốt ruột thì chỉ muốn cổ vũ kiểu “Làm luôn cả Records và Tuples đi! Thậm chí có thể bỏ qua cuộc chiến cú pháp Pipe cũng được!”

    • Records và Tuples có vẻ khó có khả năng được phát hành, hoặc ít nhất là rất khó được phát hành với ngữ nghĩa đồng nhất như mọi người mong muốn
      Theo mình hiểu thì các nhà cung cấp trình duyệt hiện đã phản đối khá mạnh việc bổ sung kiểu nguyên thủy mới ở thời điểm này. Độ khó của chuyện cơ chế đồng nhất nên hoạt động ra sao được giải thích trong chuỗi này: https://github.com/tc39/proposal-record-tuple/issues/387
      Ban đầu mình không nghĩ BigInt sẽ được dùng nhiều đến vậy, nhưng trên thực tế lại liên tục xuất hiện nhu cầu về các collection có đồng nhất cấu trúc, nên khá tiếc
      Mình cũng hiểu là việc phản đối bổ sung kiểu nguyên thủy mới đang ảnh hưởng cả đến pattern matching, nhưng không rõ lý do cụ thể, và mình cũng theo dõi đề xuất đó ít hơn
    • Temporal sắp đến là điều tốt, và còn nhiều tính năng hay khác nữa, nhưng với những đề xuất cụ thể đã nhắc đến thì khó mà lạc quan
      Pipeline, pattern matching và Records+Tuples đều đã được làm hơn 4 năm mà vẫn chỉ dừng ở giai đoạn 1~2. Trong 1 năm qua hầu như không thấy tiến triển đáng kể nào, ngoại trừ có lẽ là pattern matching
      Theo các issue trong kho Records và Tuples thì đã có phản ứng trái chiều về ngữ nghĩa giá trị, tức là liệu === có thể hoạt động hay không. Nếu bỏ ngữ nghĩa giá trị thì tính hữu ích của đề xuất giảm đi rất nhiều
      Để chúng lên được giai đoạn 3 có lẽ còn cần ít nhất 1~2 năm nữa, hoặc thậm chí có thể không bao giờ tới được. Dù vậy thì ít ra cũng đã có hàm nhóm mảng
    • Thứ mình muốn là pattern matching: https://tc39.es/proposal-pattern-matching/
      Tiếc là nó vẫn mới ở giai đoạn 1, nên có lẽ còn mất thêm vài năm nữa
    • Nếu nói về Records, mình tự hỏi Dictionary là đề xuất của ECMA5 hay là một tính năng đặc thù của AS3
      Dictionary trong AS3 là một kiểu cho phép dùng tham chiếu đối tượng, chuỗi và số làm khóa duy nhất, rồi gắn giá trị thuộc bất kỳ kiểu nào. Việc garbage collection cũng được xử lý để nó không trở thành tham chiếu yếu miễn là chính đối tượng dictionary đó còn tồn tại
      Hãy hình dung như Set của JavaScript, nhưng có thể dùng bất kỳ loại khóa nào đã chỉ định với kiểu mạnh, và sẽ báo lỗi ngay ở thời điểm biên dịch. Mình nhớ ngôn ngữ đó
    • Đây không chỉ là vấn đề của riêng các nhà làm trình duyệt lớn. Hồi ES6 vừa sắp ra, mình từng xây một suy luận engine cho JavaScript, hỗ trợ ES5 khá tốt, nhưng rồi phải bỏ cuộc khi làn sóng cập nhật cú pháp ập tới
      Những cập nhật đó gần như đã làm hỏng hệ sinh thái JavaScript, và giờ có cảm giác chỉ còn lại các ngôn ngữ biên dịch sang JS. Người vẫn còn dùng vanilla JS lúc này giống như người làm ứng dụng bằng assembly vậy
  • Mình tò mò không biết dữ liệu múi giờ trong Temporal được giữ cập nhật như thế nào
    Có phải TC39 cập nhật dữ liệu ở đâu đó rồi mỗi trình duyệt sẽ sao chép dữ liệu đó vào bên trong và phát hành phiên bản mới không, hay nếu người dùng chưa cập nhật lên bản trình duyệt có dữ liệu mới thì website của mình sẽ hiển thị giờ sai?
    Ví dụ, Mexico đã bãi bỏ giờ mùa hè vào năm 2022: https://en.wikipedia.org/wiki/Time_in_Mexico
    Với các thư viện bên thứ ba như pytz hay moment-timezone, chỉ cần cập nhật thư viện phía server là được, còn nếu xử lý trong thư viện chuẩn thì chỉ cần nâng phiên bản ngôn ngữ; nhưng với Temporal và trình duyệt của khách truy cập thì mình không rõ sẽ thế nào

    • Đọc phần “Time Zones and Resolving Ambiguity” trong tài liệu đề xuất thì chỉ thấy nói rằng nó dùng cơ sở dữ liệu múi giờ IANA, chứ không nói khi nào dữ liệu được cập nhật: https://tc39.es/proposal-temporal/docs/timezone.html
      Có vẻ máy tính của người dùng cũng có thể truy cập cơ sở dữ liệu này và xử lý cập nhật, nhưng mình không chắc. Cũng có thể trình duyệt sẽ tự tải và duy trì cơ sở dữ liệu đó riêng, và có lẽ điều này tùy vào từng cách triển khai
      Cơ sở dữ liệu liên quan: https://en.wikipedia.org/wiki/Tz_database
    • Vì đây là tính năng tích hợp trong trình duyệt nên có lẽ nó sẽ được cập nhật cùng với bản cập nhật trình duyệt. Các nhà cung cấp trình duyệt đã làm rất nhiều để đẩy nhanh việc cập nhật, và trên máy tính của người dùng trung bình thì trình duyệt có lẽ là phần mềm được giữ mới nhất
    • Trình duyệt vốn đã phải giữ thông tin locale luôn cập nhật cho các helper của Intl, nên nếu tìm hiểu hướng đó thì có thể sẽ ra câu trả lời tương tự
    • Trên các hệ Unix, tức các bản phân phối Linux, macOS và Android, đều có bản sao IANA Time Zone Database ở cấp hệ thống. Mình không rõ trình duyệt dùng bản đó hay mang theo bản sao riêng, nhưng Temporal chắc chắn dùng IANA tzdb
      Nếu người dùng không cập nhật trình duyệt hoặc hệ thống để nhận dữ liệu múi giờ mới thì khả năng họ thấy giờ sai nhìn chung là đúng. Tuy nhiên điều này cũng không khác mấy so với thông lệ hiện tại
      Phương án khác là mọi ứng dụng đều mang theo tzdb riêng, và một số ứng dụng đúng là làm như vậy trong những trường hợp hợp lý. Nhưng nhìn chung đó là sự lãng phí, làm tăng bất nhất giữa các ứng dụng, và còn có thể khiến chu kỳ cập nhật chậm hơn
    • Điều này sẽ tùy thuộc vào cách triển khai và hệ thống. Cuối cùng việc triển khai sẽ phải định nghĩa nhà cung cấp múi giờ, và rất có thể thứ đó sẽ được cung cấp từ các host/system hook mà phần triển khai engine đưa vào cho Temporal
  • Cần thêm một sự kiện để phát hiện khi ai đó thay đổi múi giờ
    Trong danh sách “những điều sai lầm mà lập trình viên tin về thời gian”, có lẽ cũng nên thêm câu “lập trình viên tin rằng múi giờ đang sử dụng là cố định”. Ngoài đời thực, mỗi ngày có hàng triệu người di chuyển qua các múi giờ

    • Có vẻ sự kiện như vậy sẽ trở thành một điểm dữ liệu nữa để lấy dấu vân tay người dùng và suy đoán vị trí của họ
    • Tôi không rõ sự kiện này sẽ được dùng vào đâu. Xét đến số lượng người dùng bị ảnh hưởng trong hầu hết các ứng dụng web phụ thuộc phần nào vào thời gian, tôi nghi ngờ liệu nó có đủ giá trị để phải trực tiếp lắng nghe và phản ứng với sự kiện này hay không
      Tất nhiên, nó có thể hữu ích cho các thư viện
    • Múi giờ của client chỉ nên quan trọng đối với chính client. Ngoài mục đích tiện lợi là hiển thị dấu thời gian theo giờ địa phương của người dùng, không có điều kiện nào khiến đồng hồ phía client trở nên quan trọng. Người dùng đổi múi giờ thì cũng chẳng có lý do gì phải bận tâm
    • Để theo dõi thay đổi múi giờ thì cần có trạng thái, vì vậy có lẽ đúng hơn là để lập trình viên tự định nghĩa cách theo dõi và phản ứng. Có thể không nên để Temporal áp đặt quan điểm về cách xử lý đó
    • Nếu đang ở trên máy bay hay ISS thì thậm chí có thể rơi vào trạng thái không có múi giờ nào cả
  • Việc .Now không phải là lời gọi hàm thật sự rất đáng tiếc. Nó không nên là một thuộc tính
    Nếu đánh giá .Now nhiều lần trong một vòng lặp, mỗi lần có thể cho ra giá trị khác nhau, điều này khá bất ngờ
    C# cũng đã đưa ra lựa chọn tương tự và lẽ ra không nên làm vậy: https://ericlippert.com/2014/05/19/when-should-i-write-a-pro...

    • Có vẻ bạn đã hiểu nhầm. Nownamespace của các hàm lấy giá trị thực tế, ví dụ như Now.instant()
  • Tôi thật sự rất thích đề xuất Temporal, nhưng có một điểm khiến tôi băn khoăn. Nó dựa vào tính bằng nhau theo tham chiếu khi so sánh
    Tức là Temporal.Instant.from('2020-01-01') != Temporal.Instant.from('2020-01-01')
    Bản thân điều đó không hẳn là xấu, nhưng về thực tế nó gần như loại bỏ khả năng dùng các đối tượng này làm khóa Map hoặc gom chúng vào Set. Tôi hiểu vì sao quyết định đó được đưa ra, nhưng vẫn thấy tiếc vì không làm được
    Nếu một ngày nào đó Records và Tuples thực sự xuất hiện, có lẽ sẽ có một phiên bản dựa trên chúng

    • Trong JavaScript có kiểu không nguyên thủy nào mà == cho ra tính bằng nhau không dựa trên tham chiếu không?
    • Tùy trường hợp, có vẻ có thể dùng .epochMilliseconds làm khóa/phần tử cho Map/Set. Tuy nhiên nếu cần giữ dữ liệu múi giờ trong Map hoặc cần phép toán cộng thêm trên Instant thì phải giữ lại Instant gốc ở phía value
      Với Set, có thể dùng kiểu Map{v.epochMilliseconds:v} để vẫn giữ được Instant
      Không phải cách hay ho gì, nhưng đây là vấn đề nên trách bản thân JavaScript hơn là Temporal. Có thể bắt runtime xử lý việc này, nhưng như vậy thì polyfill sẽ thất bại
    • Dù có làm được thì dùng những giá trị như vậy trong Map/Set cũng thường là ý tưởng tồi, khá giống với việc dùng số dấu chấm động trong Map/Set
    • Chẳng phải là do JavaScript không thể làm điều đó sao? Trừ phi dùng một kiểu hack kỳ quặc giống constant string pool của Java, khiến mọi đối tượng được sử dụng đều là tham chiếu tới giá trị trong một object pool toàn cục, nếu không thì rất khó
    • Sao không просто dùng String() hoặc '2020-01-01'?
  • Việc cung cấp hàm so sánh hoạt động cùng các API hiện có là một thiết kế rất vững vàng. Thậm chí có thể coi đây là điều bắt buộc phải đọc khi thêm kiểu mới
    Ví dụ, truyền Temporal.Duration.compare vào sort thì có thể sắp xếp theo thứ tự PT1H, PT1H30M, PT1H45M, PT2H. Xin gửi lời khen tới các nhà thiết kế

  • Tôi hiểu cái tên Temporal nhằm tránh xung đột với các đối tượng thời gian phổ biến như Moment hay Datetime, nhưng cái tên này không hay
    Lần đầu nhìn thấy tôi còn tưởng đó là thứ gì như điều khiển garbage collection

    • temporal có nghĩa là liên quan đến thời gian đối lập với tính vĩnh cửu, liên quan đến thì ngữ pháp hay sự phân chia thời gian, hoặc liên quan đến thời gian đối lập với không gian: https://www.merriam-webster.com/dictionary/temporal
      Nghe cũng là một cái tên ổn
    • Tôi lại tưởng đó là Temporal của workflow engine trong trình duyệt
    • Dù đây có là kiểu tranh cãi màu sơn nhà để xe về một quyết định đã chốt rồi đi nữa, tôi vẫn đồng ý rằng đây là một cái tên thật tệ
      Trước hết, Temporal không phải danh từ mà là tính từ. Nó có liên quan đến thời gian nhưng không tạo cảm giác trực quan là phù hợp
      Quan trọng hơn, nếu chọn những cái tên kỳ quặc để giảm khả năng xung đột với mã cũ, thì theo thời gian ngôn ngữ sẽ ngày càng trở nên khó hiểu hơn
      Khi thêm PromiseGenerator, cũng đã có nhiều thư viện dùng những tên đối tượng đó rồi. Không giống từ khóa, các đối tượng built-in có thể bị ghi đè nên đó không phải vấn đề lớn
      Tôi cho rằng ủy ban tiêu chuẩn nên kiên quyết dùng Time vì sức khỏe lâu dài của ngôn ngữ
      Dĩ nhiên, cuộc tranh luận này có lẽ đã qua rồi và hẳn các nhà làm trình duyệt cùng những người triển khai JS engine đã đi đến đồng thuận
    • Tôi cũng thấy đây là một cái tên kinh khủng. Thà là DateV2 còn hơn
      Tôi hiểu cần tương thích ngược, nhưng Temporal nghe rất gượng. DateTime thậm chí còn không phải là tên có trong chuẩn JS, nên tôi không hiểu vì sao họ không dùng nó. Cho đến lúc đó, chắc tôi sẽ để const DateTime = Temporal
  • Bài liên quan:
    JavaScript Temporal Is Coming - https://news.ycombinator.com/item?id=42809834 - tháng 1 năm 2025, 18 bình luận
    Mozilla: Temporal (Limited Availability) - https://news.ycombinator.com/item?id=42776548 - tháng 1 năm 2025, 1 bình luận
    Is It Time for the JavaScript Temporal API? - https://news.ycombinator.com/item?id=29712118 - tháng 12 năm 2021, 100 bình luận
    Temporal: Getting started with JavaScript's new date time API - https://news.ycombinator.com/item?id=27661667 - tháng 6 năm 2021, 194 bình luận
    JavaScript Temporal - https://news.ycombinator.com/item?id=27395236 - tháng 6 năm 2021, 1 bình luận
    JavaScript Proposal Temporal for Dates is now stage 3 - https://news.ycombinator.com/item?id=26432346 - tháng 3 năm 2021, 1 bình luận

    • Dù đáng mừng khi các Web API dạo này đã thực sự trở nên rất xuất sắc, việc bài đăng đầu tiên về chủ đề này đã là từ gần 4 năm trước, vào tháng 3 năm 2021, vẫn khiến tôi thấy tiếc
      Câu “con tàu lớn đổi hướng thì chậm” đúng là quá chuẩn