代码之家  ›  专栏  ›  技术社区  ›  billy

异步Javascript:尝试以间隔多次调用ajaxapi?

  •  0
  • billy  · 技术社区  · 6 年前

    所以我有一个表单,用户搜索一个查询。

    我一直在进行API调用。第一个查询由用户输入,然后程序根据实体分析进行新的查询,并反复进行API调用。

    来自API结果的新查询。

    控制台中的结果:

    queries length is zero...
    Iterating...  undefined
    On Queue Searches #1:  []
    query length is zero
    POST / 200 15.747 ms - -
     etc. etc. etc.
    

    将用户输入的查询推送到数组中,并将其发送到 onQueueSearch 以设置的间隔进行API调用。

    // Global Queries
    const queries = new Array();
    let counter = 0; // Just to keep track
    
        router.post('/', async (req, res) => {
            // Assign first query
            queries.push(req.body.searchTerm);
            // Invoke the async iterator
            const results = await queryIterator(queries);
            res.send(results);
           });
    

    这个函数可能有问题吗? 对于数组中的每个查询,一定要将其传递给分析哪些API调用,假设此函数以设置的间隔一致地调用API。 (注意:新查询将添加到API调用中的查询数组中。)

    async function onQueueSearch() {
    
          if(queries.length === 0 ) {
            console.log("queries length is zero...");
            return; // return something if empty
          }
          // This will extract the next in queue and remove it from queries    
          return await sentimentAnalyze(queries.pop); 
      }
    
    // Define functions for Async Iterator -----
    async function* queryGenerator() {
      while (true) {
          yield await onQueueSearch(queries.pop());
      }
    }
    
    async function queryIterator(queries) {
      for await (const result of queryGenerator()) {
          console.log('Iterating... ', result);
          console.log(`On Queue Searches #${++counter}: `, queries);
          if (!queries.length) {
              console.log("query length is zero");
              return result;
          }
      }
    }
    

    来自twitter google api和returns

    async function sentimentAnalyze(searchValue) {
      try {
         const tweetDocumentObject = await searchTwitter(searchValue);
         const sentimentResults = await googleSentimentAnalyze(tweetDocumentObject); 
         const entitiesResults = await googleEntityAnalyze(tweetDocumentObject);
         return {sentimentResults, entitiesResults};
     } catch(err) {
         console.log('sentimentAnalyze Error: ', err);
     }   
    }
    

    此函数用于从实体分析中添加新查询。

       function googleEntityAnalyze(document) {
      return new Promise((resolve, reject) => {
        // Detects entities in the document
        googleClient
        .analyzeEntities({document: document})
        .then(results => {
          const entities = results[0].entities;
    
          queries.unshift(req.body.searchTerm);
          entities.forEach(entity => {
              queries.unshift(entity.name);
                // console.log("Entitiy name: " +entity.name);
            // console.log(` - Type: ${entity.type} `);
            resolve({ entity  });
          });
        })
        .catch(err => {
          console.error('ENTITY ERROR:', err);
        });
    
      });
    }
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Gabriel Balsa Cantú    6 年前

    好吧,你的代码有几个问题,但是很容易解决如果你很小心的话,我会指导你解决它们。

    第一个:

    你是 要始终排队,这是在队列中获取相同数据的根本原因:

    queries.push(req.body.searchTerm); // searchTerm being '1'
    ... // Do more logic until googleEntityAnalyze
      entities.forEach(entity => {
        queries.push(entity.name);
        resolve({ entity  });
      });
     // Assume entities as [2, 3]
    

    现在您的队列是 [1,2,3] ,作为第一个参数为1。 然后从以下位置重做查询逻辑:

    async function onQueueSearch() {
    
      for(i = 0; i < queries.length; i++) {
        return await sentimentAnalyze(queries[i]);
         // queries[i].splice(i, 1);
      } 
    
      if(queries.length === 0 ) {
        console.log("queries length is zero...");
      }
    
    }
    

    for循环的返回将中断循环并返回第一次执行,这将是 queries[0] === 1

    因此,要解决此问题,请使用以下方法使数组保持先进先出:

    queries.unshift(req.body.searchTerm);
    entities.forEach(entity => {
        queries.unshift(entity.name);
        resolve({ entity  });
    });
    

    这将使您的查询在到达[3,2,1]时保持有序,而不是[1,2,3],现在您可以使用 queries.pop() 相反。

    queries.unshift(4); // where queries was [3,2,1], will be [4,3,2,1]
    queries.pop(); // 1
    

    将情绪分析更改为:

     async function onQueueSearch(){
    
          if(queries.length === 0 ) {
            console.log("queries length is zero...");
            return; // Return something if empty!
          }
          return await sentimentAnalyze(queries.pop());
          // This will extract the next in queue and remove it from queries    
      }
    

    您正在使用一个iterval来连续调用查询,问题是:

    setInterval(async function() { 
        results = await onQueueSearch(); 
      }, 3000);
    

    “估计” 重新执行前完成查询所需的时间。使用上面的unshift和pop查询,您可以完成这项工作,但是,您需要一个更优雅的解决方案。

    带有NodeJS版本<10+:

    const queries = [1];
    let counter = 0; // Just to keep track
    async function reRunQueries(){
        counter++;
        console.log(`queries #${counter}: `, queries);
        results = await onQueueSearch();
        console.log('Results: ', results);
        if(!!queries.length){
            return await reRunQueries();
        }else{
            return results;
        }
    }
    
    async function onQueueSearch(){
        return await longQuery(queries.pop()); 
    }
    
    async function longQuery(param){
       if(param === 6){
           // Use this as stop signal!
           return param;
       }else{
           queries.unshift(++param);
           return param;
       }
    }
    
    const RES = reRunQueries();
    RES.then(result => {
        console.log('RES: ', result);
    })
    

    知道递归的停止信号很重要,否则它永远不会结束。

    使用Iterable生成器:

    const queries = [];
    let counter = 0; // Just to keep track
    
    
    // EMULATE EXPRESS JS call ========================
    const req = { body: { searchTerm: 1 } };
    const res = {send: (val) => console.log('RECEIVED: ', val)};
    
    const router = {
        post: (route, callback) => callback(req, res)
    }
    
    router.post('/', async (req, res) => {
        // Assign first query
        queries.push(req.body.searchTerm);
        // Invoke the async iterator
        const results = await queryIterator(queries);
        res.send(results);
    });
    // The Above is for nodeJS direct testing only, 
    // > you can plug it into your own router.post declaration "as is"
    
    // -----------------------------------------
    // Define functions for Async Iterator -----
    
    async function* queryGenerator() {
        while (true) {
            yield await onQueueSearch(queries.pop());
        }
    }
    
    async function queryIterator(queries) {
        for await (const result of queryGenerator()) {
            console.log('Iterating... ', result);
            console.log(`On Queue Searches #${++counter}: `, queries);
            if (!queries.length) {
                return result;
            }
        }
    }
    
    // ------------------------------------------------------------
    // Emulate your current async requests using queries array ----
    
    async function onQueueSearch(param) {
        return await longQuery(param);
    }
    
    async function longQuery(param) {
        if (param === 6) {
            // Use this as stop signal!
            return Promise.resolve(param);
        } else {
            queries.unshift(++param);
            return Promise.resolve(param);
        }
    }
    

    /*
    Iterating...  2
    On Queue Searches #1:  [ 2 ]
    Iterating...  3
    On Queue Searches #2:  [ 3 ]
    Iterating...  4
    On Queue Searches #3:  [ 4 ]
    Iterating...  5
    On Queue Searches #4:  [ 5 ]
    Iterating...  6
    On Queue Searches #5:  [ 6 ]
    Iterating...  6
    On Queue Searches #6:  []
    RECEIVED:  6
    */