当前位置: 首页 > 知识库问答 >
问题:

如何在使用异步代码循环时维护状态

董宜然
2023-03-14

我对JS中使用Promissions或async/await的异步操作还不熟悉,我正试着对这个概念进行总结。我遇到的一个问题是,如何在多个数组上循环并对每个元素执行异步操作时保持状态。例如,我有以下代码:

const listOfStores = [{location: '123 testers lane'}, {location: '321 testers lane'}];
const listofTechs = [{location: '123 nowhere lane'}];

for(let i = 0; i < listOfStores.length; i++){
  let store = listOfStores[i];
  
  let bestDistance = Infinity;
  for(let j = 0; j < listOfTechs.length; j++){
    let tech = listOfTechs[j];
    
    let distance = await getDistance(store.location, tech.location);
    
    bestDistance = Math.min(bestDistance, distance);
    
  }
  
  console.log('Closest Tech Is ' + bestDistance + ' Miles Away')
}

async function getDistance(store, tech) {
  return new Promise(function(resolve, reject){
    // THIS WOULD ACTUALLY BE AN AJAX CALL TO AN API
    window.setTimeout(function(){
      resolve( Math.floor(Math.random() * (100 - 25) + 25));
    }, 2000);
  });
}

虽然上面的代码符合我的目的,但我试图更好地理解基于promise的代码。我意识到循环必须是同步的,逻辑才能工作,但API调用本质上是异步的。我不是在尝试创建异步代码,而是在尝试处理异步代码。暂停代码执行并等待用wait解决promise效果良好。我的理解是,基于promise的代码可以重写为异步/等待代码,反之亦然,所以我的问题是,如何在不使用异步/等待的情况下重写上面的代码?据我所知,没有办法暂停执行或维持定期promise的状态。

这个问题似乎很常见,以至于有人已经开发了一个处理它的模式,但是到目前为止我还没有找到那个模式。

注意:每个循环必须在进入下一个循环之前完成。我考虑循环遍历存储和技术数组,并创建一个promise,最终将解决该技术和存储之间的距离,然后将这些promise存储在一个数组中,并使用Promise. all()来解决所有的个人promise。但这是行不通的。首先,因为可能有数千个商店,同时解决每个商店会导致费率限制问题。如果其中一个promise被拒绝,所有()都会失败,因为可能有成千上万个promise,其中一个肯定会失败,并导致所有其他promise也失败。

非常感谢您的任何建议

谢谢

共有1个答案

米元凯
2023-03-14

我的问题是如何在不使用async/wait的情况下重写上面的代码?据我所知,没有办法暂停执行或保持定期promise的状态。

如果没有async/await,编写起来就不那么简单了,我知道除了好奇之外,没有其他理由这样做(async/await之所以添加,是为了让某些类型的异步代码更容易编写)。这是我们在async/await出现之前的做法,您可以使用第三方库为您管理循环(例如Bluebirdasync库),也可以编写自己的重复机制,而不使用语言循环构造。

下面是一个示例,我创建了一个实用函数,用于对数组进行非同步迭代:

// utility function for doing an asynchronous iteration of an array
function iterateArrayAsync(array, fn) {
    let index = 0;

    function next(val) {
        if (index < array.length) {
            return fn(array[index++]).then(next);
        }
        return val;
    }
    return Promise.resolve(next());
}

function calcBestDistance() {
    const listOfStores = [{ location: '123 testers lane' }, { location: '321 testers lane' }];
    const listOfTechs = [{ location: '123 nowhere lane' }];

    let bestDistance = Infinity;

    return iterateArrayAsync(listOfStores, (store) => {
        return iterateArrayAsync(listOfTechs, (tech) => {
            // process store, tech combination here
            return getDistance(store.location, tech.location).then(distance => {
                bestDistance = Math.min(bestDistance, distance);
            });
        });
    }).then(() => {
        // make resolved value be the bestDistance
        console.log('Closest Tech Is ' + bestDistance + ' Miles Away')
        return bestDistance;
    });
}

function getDistance(store, tech) {
    return new Promise(function(resolve, reject) {
        // THIS WOULD ACTUALLY BE AN AJAX CALL TO AN API
        setTimeout(function() {
            resolve(Math.floor(Math.random() * (100 - 25) + 25));
        }, 500);
    });
}

calcBestDistance().then(result => {
    console.log(result);
}).catch(err => {
    console.log(err);
});
 类似资料:
  • 问题内容: 列表中的每封电子邮件都将发送到服务器,并从服务器获得响应(如果它是有效的电子邮件)。 因此,在检查完所有电子邮件之后,数组应具有: 循环发送电子邮件到服务器的代码如下: 但是问题在于调用是异步的,因此,假设i = 0,则当i为0时控件将不会进入函数。因此,当i进入函数时,i的值可以是任何值,通常大于数组的长度,因此isEmailValidList [i]未定义。如果呼叫是同步的,则它将

  • 问题内容: 我有类似的东西: 设置状态仍然是异步的,那么等待此调用完成的最佳方法是什么? 本似乎并没有接受一个回调像使用。 一个例子 基于类 转换为基于功能的 在上面,我们要顺序运行每个setWhatever调用。这是否意味着我们需要设置许多不同的useEffect挂钩来复制此行为? 问题答案: 状态更新完成后,setter不会提供回调,就像React类组件中的setState一样。为了复制相同的

  • 我有点像: 设置状态仍然是异步,那么等待这个调用完成的最佳方法是什么? 似乎不像那样接受回调。 在上面,我们希望按顺序运行每个setwhater调用。这是否意味着我们需要设置许多不同的useEffect挂钩来复制这种行为?

  • 问题内容: 我们正在与节点合作,主要用于内部项目,并了解使用该技术的最佳方法。 并非来自特定的异步背景,学习曲线可能是一个挑战,但是我们已经习惯了框架和学习过程。 使我们两极分化的是,何时才是使用同步代码与异步代码的最佳时间。我们目前使用的规则是,如果任何东西与IO进行交互,那么它必须通过回调或事件发射器(即给定的)是异步的,但是可以将任何未使用IO的其他项构造为同步函数(此方法还将取决于函数本身

  • 问题内容: 我是这个Node.js的新手..我对此回调有点困惑..在我的应用程序中,我在for循环内调用异步函数调用,我想我的问题是在得到异步调用响应之前, for循环被循环。 我的代码: 搜索功能代码: 我想在成功执行1个搜索功能后执行for循环,我想我必须使用async for loop。请指导我解决此问题。 问题答案: 我将您的代码示例简化为以下几行,以使您更容易理解该概念。 先前代码的问题

  • 问题内容: 我要做的就是从PHP 发送状态代码- 但采用通用方式。两者和以及其他任何有效的HTTP状态代码均应正常工作。 我确实知道,您可以将状态代码指定为的第三个参数。遗憾的是,这仅在您指定时有效。因此,呼吁并 没有 工作。 而且我知道,可以通过带有状态行的呼叫发送状态代码: 但是要做到这一点,我必须为所有状态码()维护一个原因短语数组()。我不喜欢这样的想法,因为它某种程度上是PHP已经做的事