paint-brush
Mọi thứ bạn cần biết về lời hứa, khả năng và đánh giá lười biếngby@austingil
1,619
1,619

Mọi thứ bạn cần biết về lời hứa, khả năng và đánh giá lười biếng

Austin Gil5m2023/01/20
Read on Terminal Reader

Trong năm mới, tôi sẽ chỉ cho bạn cách biến `Lời hứa` trở nên lười biếng hơn. Hãy xem một ví dụ cơ bản về `Lời hứa'. Ở đây, tôi có một chức năng gọi là ngủ mất thời gian tính bằng mili giây và một giá trị. Nó trả về một lời hứa sẽ thực thi `setTimeout` trong số mili giây mà chúng ta nên đợi.
featured image - Mọi thứ bạn cần biết về lời hứa, khả năng và đánh giá lười biếng
Austin Gil HackerNoon profile picture

Đã bắt đầu một năm mới, và trong khi nhiều người hứa hẹn sẽ năng động hơn, tôi sẽ chỉ cho bạn cách làm cho Promise trở nên lười biếng hơn… JavaScript Promise s, đó là.


Nó sẽ có ý nghĩa hơn trong một thời điểm.

Đầu tiên, hãy xem một ví dụ cơ bản về Promise . Ở đây, tôi có một chức năng gọi là ngủ mất thời gian tính bằng mili giây và một giá trị. Nó trả về một lời hứa sẽ thực thi setTimeout trong số mili giây mà chúng ta nên đợi; sau đó Lời hứa giải quyết với giá trị.


 /** * @template ValueType * @param {number} ms * @param {ValueType} value * @returns {Promise<ValueType>} */ function sleep(ms, value) { return new Promise((resolve) => { setTimeout(() => resolve(value), ms); }); }


Nó hoạt động như thế này:


Bảng điều khiển JavaScript có mã, "chờ ngủ (1000, 'Ngáp & duỗi')". Rồi sau một giây, "'Ngáp và vươn vai'"


Chúng ta có thể đợi chức năng sleep với các đối số 1000'Yawn & stretch' và sau một giây, console sẽ ghi lại chuỗi 'Yawn & stretch'.


Không có gì quá đặc biệt về điều đó. Nó có thể hoạt động như bạn mong đợi, nhưng sẽ hơi lạ nếu chúng ta lưu trữ nó như một biến để await sau này, thay vì await Promise được trả lại ngay lập tức.


 const nap = sleep(1000, 'Yawn & stretch')


Bây giờ, giả sử chúng ta thực hiện một số công việc khác cần có thời gian (chẳng hạn như nhập ví dụ tiếp theo), rồi await biến nap .


Gõ vào bảng điều khiển JavaScript, "chờ ngủ trưa" và ngay lập tức thấy phản hồi "'Ngáp & vươn vai'"

Bạn có thể mong đợi độ trễ một giây trước khi giải quyết, nhưng trên thực tế, nó giải quyết ngay lập tức. Bất cứ khi nào bạn tạo một Promise , bạn sẽ khởi tạo bất kỳ chức năng không đồng bộ nào mà nó chịu trách nhiệm.


Trong ví dụ của chúng tôi, thời điểm chúng tôi xác định biến nap , Promise được tạo để thực thi setTimeout . Bởi vì tôi là một người đánh máy chậm, Promise sẽ được giải quyết khi chúng tôi await nó.


Nói cách khác, Promise s háo hức. Họ không đợi bạn await họ.


Trong một số trường hợp, đây là một điều tốt. Trong các trường hợp khác, nó có thể dẫn đến việc sử dụng tài nguyên không cần thiết. Đối với những trường hợp đó, bạn có thể muốn thứ gì đó trông giống như Promise , nhưng sử dụng lười đánh giá để chỉ khởi tạo khi bạn cần.


Trước khi chúng ta tiếp tục, tôi muốn cho bạn thấy một điều thú vị.


Promise s không phải là thứ duy nhất có thể được await ed trong JavaScript. Nếu chúng ta tạo một Object đơn giản bằng phương thức .then() , chúng ta thực sự có thể await đối tượng đó giống như bất kỳ Promise nào.


Bảng điều khiển JavaScript có nội dung "await { then: () => console.log('🙃') }" theo sau là "🙃".

Điều này hơi lạ, nhưng nó cũng cho phép chúng ta tạo các đối tượng khác nhau trông giống như Promise nhưng không phải vậy. Những đối tượng này đôi khi được gọi là “ đồ gia dụng “.


Với ý nghĩ đó, hãy tạo một cái mới tầng lớp được gọi là LazyPromise mở rộng hàm tạo Promise tích hợp sẵn. Việc mở rộng Promise không thực sự cần thiết, nhưng nó làm cho nó trông giống với Promise hơn bằng cách sử dụng những thứ như instanceof .


 class LazyPromise extends Promise { /** @param {ConstructorParameters<PromiseConstructor>[0]} executor */ constructor(executor) { super(executor); if (typeof executor !== 'function') { throw new TypeError(`LazyPromise executor is not a function`); } this._executor = executor; } then() { this.promise = this.promise || new Promise(this._executor); return this.promise.then.apply(this.promise, arguments); } }


Phần cần tập trung vào là phương thức then() . Nó chiếm đoạt hành vi mặc định của một Promise tiêu chuẩn để đợi cho đến khi phương thức .then() được thực thi trước khi tạo một Promise thực sự.


Điều này tránh khởi tạo chức năng không đồng bộ cho đến khi bạn thực sự yêu cầu nó. Và Nó hoạt động cho dù bạn gọi rõ ràng .then() hay sử dụng await .


Bây giờ, hãy xem điều gì sẽ xảy ra nếu chúng ta thay thế Promise trong chức năng sleep ban đầu bằng LazyPromise . Một lần nữa, chúng ta sẽ gán kết quả cho một biến nap .


 function sleep(ms, value) { return new LazyPromise((resolve) => { setTimeout(() => resolve(value), ms); }); } const nap = sleep(1000, 'Yawn & stretch')


Sau đó, chúng tôi dành thời gian để gõ dòng await nap và thực hiện nó.


Nhập vào bảng điều khiển JavaScript, "chờ ngủ trưa" và sau một giây trì hoãn, sẽ thấy phản hồi "'Ngáp & vươn vai'"


Lần này, chúng ta thấy độ trễ một giây trước khi Promise được giải quyết bất kể thời gian đã trôi qua kể từ khi biến được tạo.


(Lưu ý rằng việc triển khai này chỉ tạo Promise mới một lần và tham chiếu nó trong các lần gọi tiếp theo. Vì vậy, nếu chúng ta await nó một lần nữa, nó sẽ giải quyết ngay lập tức giống như bất kỳ Promise bình thường nào)


Tất nhiên, đây là một ví dụ tầm thường mà bạn có thể sẽ không tìm thấy trong mã sản xuất, nhưng có nhiều dự án sử dụng các đối tượng giống như Promise - được đánh giá lười biếng. Có lẽ ví dụ phổ biến nhất là với cơ sở dữ liệu ORM s và trình tạo truy vấn như Knex.js hoặc là lăng kính .


Hãy xem xét mã giả dưới đây. Nó được lấy cảm hứng từ một số trình tạo truy vấn sau:


 const query = db('user') .select('name') .limit(10) const users = await query


Chúng tôi tạo một truy vấn cơ sở dữ liệu chuyển đến bảng "user" và chọn mười mục nhập đầu tiên và trả về tên của chúng. Về lý thuyết, điều này sẽ hoạt động tốt với Promise thông thường.


Nhưng nếu chúng ta muốn sửa đổi truy vấn dựa trên các điều kiện nhất định như tham số chuỗi truy vấn thì sao? Sẽ thật tuyệt nếu có thể tiếp tục sửa đổi truy vấn trước khi chờ Promise .


 const query = db('user') .select('name') .limit(10) if (orderBy) { query.orderBy(orderBy) } if (limit) { query.limit(limit) } if (id) { query.where({ id: id }) } const users = await query


Nếu truy vấn cơ sở dữ liệu ban đầu là một Promise tiêu chuẩn, nó sẽ háo hức khởi tạo truy vấn ngay khi chúng ta gán biến và chúng ta sẽ không thể sửa đổi truy vấn đó sau này.


Với đánh giá lười biếng, chúng tôi có thể viết mã như thế này dễ theo dõi hơn, cải thiện trải nghiệm của nhà phát triển và chỉ thực hiện truy vấn một lần khi chúng tôi cần.


Đó là một ví dụ mà đánh giá lười biếng là tuyệt vời. Nó cũng có thể hữu ích cho những việc như xây dựng, sửa đổi và sắp xếp các yêu cầu HTTP.


Lazy Promise s rất tuyệt vời cho các trường hợp sử dụng phù hợp, nhưng điều đó không có nghĩa là chúng nên thay thế mọi Promise . Trong một số trường hợp, sẽ rất hữu ích nếu bạn háo hức khởi tạo và chuẩn bị sẵn phản hồi càng sớm càng tốt.


Đây là một trong những tình huống “còn tùy”. Nhưng lần tới khi ai đó yêu cầu bạn thực hiện một Promise , hãy cân nhắc việc lười biếng thực hiện nó ( ͡° ͜ʖ ͡°).


Cảm ơn bạn rất nhiều vì đã đọc. Nếu bạn thích bài viết này, xin vui lòng chia sẻ nó . Đó là một trong những cách tốt nhất để hỗ trợ tôi. Bạn cũng có thể Hãy đăng ký để nhận thư mới từ tôi hoặc là theo dõi tôi trên Twitter nếu bạn muốn biết khi bài báo mới được xuất bản.


Được xuất bản lần đầu vào austingil.com .