dojo 在循环中调用异步函数的层次结构?

oogrdqng  于 2022-12-16  发布在  Dojo
关注(0)|答案(5)|浏览(218)

我正在进行一个异步调用,该调用查询服务上的数据库,但此服务有一个一次输出数量的限制,因此我需要通过它发送的结果检查它是否达到了限制,并重复查询,直到它没有达到为止。
同步实体模型:

var query_results = [];

var limit_hit = true; #While this is true means that the query hit the record limit
var start_from = 0; #Pagination parameter

while (limit_hit) {
    Server.Query(params={start_from : start_from}, callback=function(result){
        limit_hit = result.limit_hit;
        start_from = result.results.length;
        query_result.push(result.results);
    }
}

字符串
显然,上面的方法不起作用,我在这里看到了一些关于这个问题的其他问题,但是他们没有提到当你需要每个迭代等待最后一个迭代完成,并且你事先不知道迭代的数量时该怎么做。
我怎样才能把上面的异步化呢?我愿意使用类似承诺/延迟的逻辑来回答,但最好是干净的。
我可能会想到一种使用等待/超时的可怕方法,但必须有一种干净、聪明和现代的方法来解决它。

  • 另一种方法是进行“预查询”以事先了解特征的数量,这样您就可以知道循环的数量,我不确定这是否是正确的方法。*

在这里,我们有时会使用Dojo,但是我找到的示例并没有解释当您有未知数量的循环https://www.sitepen.com/blog/2015/06/10/dojo-faq-how-can-i-sequence-asynchronous-operations/时该怎么做

txu3uszq

txu3uszq1#

虽然已经有很多答案了,但我仍然相信async/await是最干净的方法。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
你可能需要巴别塔
https://babeljs.io/
JS异步逻辑语法从callbackpromise再到async/await,它们都做同样的事情,当callback嵌套很多时,我们需要像链一样的东西,然后承诺来了,当promise进入循环时,我们需要一些东西使链更普通更简单,然后async/await来了。但不是所有的浏览器都支持新语法,因此,babel会将新语法编译为旧语法,这样您就可以始终使用新语法进行编码。

getData().then((data) => {
  //do something with final data
})

async function getData() {
  var query_results = [];

  var limit_hit = true;
  var start_from = 0;
  
  //when you use await, handle error with try/catch
  try {
    while (limit_hit) {
      const result = await loadPage(start_from)
      limit_hit = result.limit_hit;
      start_from = result.results.length;
      query_result.push(result.results);
    }
  } catch (e) {
    //when loadPage rejects
    console.log(e)
    return null
  }
  return query_result
}

async function loadPage(start_from) {
  //when you use promise, handle error with reject
  return new Promise((resolve, reject) => Server.Query({
    start_from
  }, (result, err) => {
    //error reject
    if (err) {
      reject(err)
      return
    }
    resolve(result)
  }))
}
lp0sw83n

lp0sw83n2#

如果你想使用一个循环,那么我认为没有(干净)的方式来做它没有承诺。
一种不同的办法如下:

var query_results = [];

var start_from = 0;

funciton myCallback(result) {  
  if(!result) {
    //first call
    Server.Query({ start_from: start_from}, myCallback);
  } else {
    //repeated call
    start_from = result.results.length
    query_result.push(result.results);
    
    if(!result.limit_hit) {
      //limit has not been hit yet
      //repeat the query with new start value
      Server.Query({ start_from: start_from}, myCallback);
    } else {
        //call some callback function here
    }
  }
}

myCallback(null);

你可以称之为递归的,但是由于查询是异步的,你不应该有调用栈限制等问题。
在ES6环境中使用promises,您可以使用async/await,我不确定Dojo是否可以这样做。

x6492ojm

x6492ojm3#

在编写速率限制器或队列之前,您不会理解回调;)诀窍是使用计数器:在异步请求之前递增计数器,并在获得响应时递减计数器,这样您就知道有多少请求处于“飞行”状态。
如果服务器阻塞了,您需要将项目放回队列中。
您需要考虑的事项有很多:如果进程被终止,队列会发生什么变化?在发送另一个请求之前要等待多长时间?确保回调没有被调用很多次!您应该重试多少次?在放弃之前要等待多长时间?确保没有遗漏!(回调永远不会被调用)
当所有的边缘情况都考虑进去的时候,你会得到一个相当长而且不那么优雅的解。但是你可以把它抽象成一个函数!(它返回一个Promise或者任何你喜欢的)。如果你有一个用户界面,你也想显示一个加载条和一些统计信息!

8cdiaqws

8cdiaqws4#

每次都必须等待服务器响应。这里是一个封装的方法

var query = (function(){
  var results = [];
  var count = 0;
  return function check(fun){
    Server.Query({ start_from: count}, function(d){
      count = d.results.length;
      results.push(d.results);
      if (d.limit_hit && fun) fun(results);
      else check(fun);
    });
  };
})();

// Call here
var my_query = query(function(d){
  // --> retrive all data when limit_hit is true)
});
dddzy1tm

dddzy1tm5#

您可以使用生成器函数Generators来实现这一点对于POC:
一些基础知识-使用星号*定义一个生成器-它公开一个返回下一个值的next函数-生成器可以在内部使用yield语句暂停,也可以在外部通过调用next()继续- While(true)将确保生成器在limit到达之前不会完成

function *limitQueries() {
  let limit_hit = false;
  let start_from  = 0;
  const query_result = [];

  while (true) {
    if (limit_hit) {break;}
    yield Server.Query(params={start_from : start_from}, 
        callback=function* (result) {
        limit_hit = result.limit_hit;
        start_from = result.results.length;
        yield query_result.push(result.results);
    }
  }
}

显然,生成器函数保持着它自己的状态。生成器函数公开了两个属性{ value, done },你可以这样调用它

const gen = limitQueries();
let results = [];
let next = gen.next();

while(next.done) {
  next = gen.next();
}
results = next.value;

您可能需要使用Server.Query方法来处理生成器回调。希望这对您有所帮助!干杯!

相关问题