Около полумесяца назад вышел TypeScript 5.2. В этой новой версии появилось новое ключевое слово using
, которое, по-видимому, заимствовано из C#.
Я не собираюсь говорить о том, что он обещает или как его использовать, скорее, я собираюсь раскритиковать его и рассказать о причине, по которой я предлагаю нам не использовать его в нашей кодовой базе.
Самая первая причина заключается в том, что сочетание асинхронных функций выглядит странно. Нам нужно использовать await using
, что это за черт? Разве транспилятор или среда выполнения не могут обнаружить, что ресурс использует Symbol.asyncDispose
вместо Symbol.dispose
, и автоматически разрешить закрытие в асинхронном контексте для нас за кулисами и позволить нам просто использовать чистое ключевое слово using
и сохранить наш код чистым и понятным?
Вторая причина заключается в том, что полагаться на вышестоящие API для реализации функций очистки ненадежно, даже авторы библиотек готовы добавить такую функцию. Что происходит с пользователями, которые все еще используют старую версию библиотеки? Наверняка могут заставить пользователя обновиться, точно так же, как некоторые библиотеки сейчас поддерживают только ES-модули и больше не поддерживают CommonJS, но это плохо, возьмем, к примеру, nonoid.
Возможно, обновить зависимость и несложно, но как насчет самой среды выполнения Node.js? Скажем, если Node v20 реализует API утилизации в пакете fs, будем ли мы рады его использовать? Я так не думаю. Как активный и увлеченный разработчик, я люблю пробовать что-то новое на своей машине, поэтому, очевидно, я запускаю новейшую версию Node.js. Но моя производственная среда уже не та, в которой по какой-то причине все еще работает Node.js v16, и обновить производственную среду не так-то просто. Что, если я использую новое ключевое слово using
в своей базе кода, и оно работает нормально, и я этому рад, но когда я пытаюсь развернуть новые обновления, производственная среда просто перестает работать.
Третья причина в том, что мы не знаем, стоит ли нам использовать эту функцию или нет. Что касается вышеизложенных причин, если вышестоящий API возвращает объект, который реализует новую функцию, но меня беспокоят проблемы совместимости, особенно когда я разрабатываю общие библиотеки, которые потенциально могут использоваться разными людьми в разных средах, я бы хотелось бы поддерживать как можно больше версий Node.js. Итак, я решил не использовать ключевое слово using
, что тогда мне следует использовать? Я надеюсь, что вышестоящая библиотека предоставит другой API, который не использует функцию удаления, чего не следует делать, потому что это было бы странно и противоречиво.
В то время как другие языки становятся все лучше и лучше, TypeScript/JavaScript становится все страннее и страннее. В Python 3.13 будет исключен GIL, что позволит языку поддерживать настоящую многопоточность, позволяющую выполнять параллельные задачи на многоядерных машинах. Поэтому я не могу не спросить: что не так с дизайном TypeScript сегодня?
Я некоторое время программировал на Golang. В Golang у нас есть ключевое слово defer
, которое является лучшим решением для явного управления ресурсами. Это не только снижает вероятность того, что вы забудете освободить ресурс, но и поддерживает более широкий спектр работ по очистке, а не только закрытие некоторых файлов и отключение от базы данных, но также может выполнять другие задачи. Например, если мы запускаем дочерний процесс в фоновом режиме, мы можем немедленно вызвать функцию kill с ключевым словом defer
, и после завершения функции это гарантирует, что дочерний процесс также будет завершен.
Известно, что TypeScript перенимает функции других языков, так почему бы не использовать ключевое слово defer
. Я полагаю, причина в том, что это разработка Microsoft, и на нее сильнее влияет C#, а не Go.
К счастью, JS — очень свободный язык. Хотя у нас не может быть встроенной поддержки defer
, мы можем ее смоделировать, и я сделал это в своем недавнем проекте. Дочерний процесс, о котором я упоминал выше, на самом деле представляет собой сценарий в этом проекте, который используется в модульных тестах для создания дочернего процесса для запуска gRPC-сервера, к которому программа может подключиться и остановить после завершения функции тестирования. Я не буду рассказывать о деталях этого проекта, но хотел бы опубликовать несколько фотографий кода, который использует функцию defer
как в TypeScript, так и в Golang, просто он выглядит просто и правильно.
Следующие ссылки представляют собой репозитории, упомянутые на изображениях, посмотрите, если вам интересно.