Одностраничное приложение — это веб-приложение, которое требует от браузера загрузки только одной страницы. Веб-приложение или веб-сайт взаимодействуют с браузером, динамически перезаписывая текущую страницу данными с веб-сервера.

В настоящее время я разрабатываю одностраничное приложение, представляющее собой своего рода игру для нескольких человек, которая выбирает игроков, за которых проголосовало больше всего результатов поиска Yelp. Он использует Yelp «Fusion API» и получает результаты Yelp для пользователя, создает имена игроков и просит пользователей голосовать по одному за каждый результат. Каждый результат, за который проголосовали все игроки, затем отображается в списке матчей с информацией и ссылками на страницы результатов Yelp.

За время разработки многих приложений и проектов я еще не создал ничего, что было бы столь же увлекательным или приятным в работе, как этот самый последний проект с использованием бэкэнда Rails для создания API, который я использовал для обслуживания внешнего интерфейса. Раньше у меня был опыт работы с Rails, но я обнаружил, что готовому проекту не хватает динамичности и интерактивности, которых так жаждет любой конечный продукт. Чего мне не хватало, так это ядра всех интерактивных и динамических веб-приложений, а именно JavaScript.

Руби и JS

Раннее направление и планирование проекта, подобного этому, имеют важное значение. Поскольку есть две части, работающие вместе, важно решить, какие части будут выполнять какие действия и обязанности. Важным шагом в этом процессе является решение, какие модели будут находиться на лицевой стороне, а какие — на оборотной. Я использовал внешний API, созданный Yelp, под названием «Fusion API». Я использовал это для создания игры, в которой несколько пользователей по очереди голосовали «нравится» или «не нравится» для каждого результата. Поскольку результаты поиска относятся только к одной игре, я создаю класс JS для результатов Yelp. Однако, чтобы сохранить пользователей и лайки в базе данных, я использую fetch() для добавления пользователей и идентификатора Yelp Fusion для каждого результата, который нравится каждому игроку. Пользователи и идентификаторы результатов Yelp Fusion, которые им понравились. Это также позволяет при построении каждого экземпляра класса добавлять только те атрибуты, которые имеют отношение к нашему приложению.

В Rails есть возможность оптимизировать ваше приложение для использования в создании API. API — это сокращение от интерфейс прикладной программы. В контексте моего приложения он содержит объекты формата JSON, которые ссылаются на модели на стороне сервера. Я использовал функцию JS под названием fetch(), которая принимает в качестве аргумента URL-адрес для запроса и объект конфигурации, который определяет команду HTTP и заголовки. Выполнение действий над полученными данными — это то, что позволяет нам обновлять DOM (модель объекта-документа) без рендеринга новой страницы. Функция fetch() определяется MDN как таковая –

«Fetch API предоставляет интерфейс JavaScript для доступа и управления частями конвейера HTTP, такими как запросы и ответы».

«Этот метод возвращает обещание, которое вы можете использовать для получения ответа на запрос. Метод fetch имеет только один обязательный аргумент — URL-адрес ресурса, который вы хотите получить».

Одной из проблем, с которой сталкивается любой новичок в Fetch, является его асинхронный характер. Вот пример из моего кода, в котором мне пришлось обойти это.

function getAllLikes() {
    const allLikes = []
    USERARY.forEach( (user, i) => {
        fetch(`http://localhost:3000/users/likes?name=${x}`)
                .then(response => {
                    return response.json()
                    })
                .then(json => {
                    json['data']['attributes']['likes'].forEach( like => {
                        allLikes.push(like.yelp_id)
                    })
                    return i
                })
                .then(i => {
                    if (i === USERARY.length - 1) {renderMegamatch(allLikes)}
                })
                .catch(err => {
                    console.log(err)
                    }); 
    });
};

В этом примере вы можете видеть, что у меня есть функция getAllLikes(), которая выполняет итерацию по массиву пользователей и вызывает вызовы URL-адреса, соответствующего контроллеру в бэкэнде, чтобы получать лайки каждого из этих пользователей. Я использую .then(), который принимает функцию в качестве аргумента и использует возвращаемое значение функции .then(), которая была вызвана в качестве аргумента внутренней функции .then(). Я хотел передать каждый лайк в массив с именем allLikes, а затем вызвать другую функцию renderMatch() с массивом лайков в качестве аргумента. Вы можете видеть, что я поместил вызов renderMatches() внутри функции .then(), которая находится внутри fetch(), чтобы она вызывала функцию только после завершения метода forEach().

Из-за асинхронной природы Fetch, если вызов renderMatch() находится за пределами этого вызова выборки, он вызовет renderMatch() до завершения итерации по пользовательскому массиву, потому что выборка должна дождаться ответа от сервера, поэтому считыватель JS пропускает его и продолжает через функция.

Первоначально опубликовано на https://jcguest.github.io 17 апреля 2020 г.