как я могу мгновенно отобразить отсканированный массив URL-адресов сайта на стороне клиента?

#node.js #graphql #apollo-server

#node.js #graphql #apollo-сервер

Вопрос:

Я сканирую карту сайта сайта с помощью apollo server. но когда я отправляю запрос с playground, он выдает результаты, не дожидаясь завершения функции. Как я могу приостановить сканирование для получения результата? И как я могу мгновенно отобразить отсканированный массив URL-адресов сайта на стороне клиента?

Если я использую подписку graphql, мне нужно сохранять данные один за другим. это было бы много данных.

Примечание: система работает, и данные сохраняются в mongoose.

 scanSitemap: async (parent, { id, data }, { WebLink }) => {

    let dataset = [];

    const generator = await SitemapGenerator('https://example.org', {
      stripQuerystring: false,
      filepath: null
    });

    generator.start();

    generator.on('add', (url) => {
      dataset.push(url);
      console.log(dataset);
    });

    generator.on('done', () => {
      return new WebLink({
        status: 1, domain: 'test', websiteId: id, urls: dataset
      }).save();
    });

  },
 

Ответ №1:

В этом случае ваш scanSitemap распознаватель должен возвращать a Promise , который разрешается только при 'done' отправке события из SitemapGenerator

Почему? Ну, согласно документам ApolloServer:

Распознаватели часто выполняют асинхронные действия, такие как выборка из базы данных или внутреннего API. Для поддержки этого распознаватель может возвращать обещание, которое преобразуется в любой другой поддерживаемый возвращаемый тип. (https://www.apollographql.com/docs/apollo-server/data/resolvers/#return-values )

В этом случае ваш распознаватель определенно выполняет асинхронную операцию — очистку карты сайта — так что это хорошая ситуация для использования Promises.

Возвращая a Promise , вы даете указание серверу Apollo дождаться, пока будут доступны результаты вашей асинхронной операции. Согласно вашему коду, я полагаю, вы хотите решить эту проблему в конце дня:

 new WebLink({
  status: 1, domain: 'test', websiteId: id, urls: dataset
}).save()
 

Я переписал ваш код для использования Promises (я также протестировал его на своей стороне, и он работает!)

 scanSitemap: async (parent, { id, data }, { WebLink }) => {
  // Returning a new promise inside of the GraphQL resolver
  // that accepts a callback with a resolve argument that we'll use later
  return new Promise((resolve) => {
    let dataset = [];

    // No need to await SitemapGenerator
    const generator = SitemapGenerator('https://example.org', {
      filepath: null,
      stripQuerystring: false,
    });

    generator.start();

    generator.on('add', (url) => {
      dataset.push(url);
      console.log(dataset);
    });

    generator.on('done', () => {
      // Resolving the promise
      // and telling ApolloServer that our GraphQL resolver result is ready
      resolve(
        new WebLink({
          domain: 'test',
          status: 1,
          urls: dataset,
          websiteId: id,
        }).save(),
      );
    });
  });
};
 

Вот отличный ресурс об обещаниях, если вы заинтересованы в дальнейшем:

https://dev.to/lydiahallie/javascript-visualized-promises-async-await-5gke