Большинство примеров в интернете образуют связку WebSocket+Ajax,
Первая причина. Чаще всего уже есть сервер, который имеет какой-то rest api и тут приходит необходимость в нотификациях или что-то подобное, вот и прикручивают ws справа.
Вторая. Вебсокет немного сложнее чем http. Надо учитывать, как шарить вызовы между инстансами сервера, ведь вебсокет может жить очень долго, в отличии от http, который выполняется не больше минуты. А так же учитывать блокировку, если какой-то метод залочит поток в котором обрабатываеся вызов, то будет большая беда. Поэтому вызовы при обработке должны быть неблокирующими(suspend, async, etc) или выполнять каждое действие в отдельном потоке, но тут потоков не хватит, да и дорого потоки плодить. В общем зависит от среды выполнения.
Третья. Формат сообщения. В вебсокете не предусмотрен какой-то один формат сообщения, каждый должен выбрать его сам. Это или json-rpc или grpc или graphql или что-то подобное, что явно говорит, что ваш вызов №X завершился с результатом Y. В противовес http, который имеет параметры и какой-то ответ на эти праметры. Один, всегда.
Четвертое. сопутствующие проблемы инфраструктуры. Часто используется nginx, и в проде вы подключаетесь не к своему(им) http серверу, а к nginx, который и держит соединение. Если отваливается одна из сторон, то вторая об этом никак не узнает сразу(а иногда и вовсе) Это решается настройкой nginx, требует знаний, в противовес http, где по умолчанию настройки минимальны. Отсюда проблема пингов и понгов, они есть в протоколе, но ими невозможно управлять из браузера. Люди просят API чтоб можно было хоть как-то обработать или pong или отправить ping, но увы и ах, этого нет. Поэтому появляются такие реализации как socket.io где ребята запихали свои самописные пинги.
Как я уже сказал, ws сложнее чем http, но не столь критично, некоторые сложности опустил в виду того, что они зависят уже от инструментов реализации, ну или просто забыл. Ну и на ваш вопрос мало ответов, потому что как вы могли заметить тема оооочень обширная.