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

异步等待函数的奇怪行为

王英彦
2023-03-14

我有以下异步代码示例:

// Functions

function getSomePromise() {
    let a = new Promise((resolve, reject) => {    
        setTimeout(function(){
            console.log("Inside promise...");
            resolve("Success!"); 
        }, 1000);
    });

    return a;
}

async function someWrapper(i) {
    console.log('A: '+ i);
    await getSomePromise();
    console.log('B: ' + i);    
}

和两个测试:

async function test1() {
    for(let i=0; i<5; i++) {
        // body copy-pasted of someWrapper function:
        console.log('A: '+ i);
        await getSomePromise();
        console.log('B: ' + i);
    }    
}

async function test2() {
    for(let i=0; i<5; i++) {
        someWrapper(i);                
    }    
}

下面是运行separatleytest1()test2()后chrome控制台中的结果:

Test 1               |      Test 2
---------------------------------------------
A: 0                 |      A: 0
Inside promise...    |      A: 1
B: 0                 |      A: 2
A: 1                 |      A: 3
Inside promise...    |      A: 4
B: 1                 |      Inside promise...
A: 2                 |      B: 0
Inside promise...    |      Inside promise...
B: 2                 |      B: 1
A: 3                 |      Inside promise...
Inside promise...    |      B: 2
B: 3                 |      Inside promise...
A: 4                 |      B: 3
Inside promise...    |      Inside promise...
B: 4                 |      B: 4

问题:为什么我们在for loop(test2)中使用函数someWrapper(),得到的结果与我们直接复制粘贴到for loop(test1)中的结果不同?

(上面的例子很抽象,但是我发现这种行为调用ajax请求(而不是console.log('A:'i);console.log('B:'i);)在我的应用程序中非常重要(请求A1必须在请求B0之前...))

共有2个答案

霍建章
2023-03-14

测试2:

在使test2异步之前,它不是异步的。您已经在test2中编写了同步代码。它们是控制台。日志test2中只有异步代码是对promise的调用。让我们把它分解一下

async function test2() {
    for(let i=0; i<5; i++) {
        someWrapper(i);                
    }    
}

上面的代码按顺序激发someWrapper()5次。因此,它编写第一个sync代码,即控制台。在控制台中连续记录('A'i)5次。

然后,每个某物Wrapper()等待asyncpromise返回parallelly.after每个promise解决它打印的内部promise。直到promise解决,执行停止,不能继续下一步

然后,在解析promise后,它打印出控制台中的第二个sync代码,即console.log('B'i)

测试1:

test1的行为将不同于test2。让我们打破它

async function test1() {
    for(let i=0; i<5; i++) {
        // body copy-pasted of someWrapper function:
        console.log('A: '+ i);
        await getSomePromise();
        console.log('B: ' + i);
    }    
}

主要区别在于您正在等待内部for循环。因此,这实际上将暂停循环,而test1的情况并非如此

因此,对于每个迭代,它将打印控制台。日志('A'i)

然后暂停迭代,等待getSomePromise()

promise返回时将打印“内部promise”

然后打印控制台。日志('B'i)

然后继续下一次迭代。

谭富
2023-03-14

看着评论

@HMR-hm。。。我不明白-在有问题的示例中,有一个异步函数someWrapper(),但该函数不返回任何东西(它甚至没有return语句(!)-你能解释一下异步函数立即返回promise是什么意思吗卡米尔·基尔切夫斯基

似乎您不理解异步等待。我通常建议人们停止工作,等待你明白promise。然而,在下一个问题下的评论中,我给你答案:

someWrapper将立即返回解析为未定义的promise。someWrapper函数中的wait only“waitis”,但调用someWrapper的函数将立即收到一个在未定义中解析的promise。函数总是返回一些东西,如果在代码中没有,那么它将返回未定义的。如果它是一个没有返回的异步函数,那么它将返回一个在undefined-HMR中解析的promise。

wait是promise的语法糖(外观更好的代码),实际上并不等待任何东西。

也许下面的代码可以清除这些内容:

js prettyprint-override">var test = async () => {
   await 22;//doesn't even matter if value is promise
   console.log("after wait");
}
var result = test();
console.log("outside test we don't wait for anything",result);
 类似资料:
  • 我正试图将图像上传到firebase存储,但调用该函数时,未执行wait以获取url。我错过了什么? 看看这个其他主题,我发现问题可能是“然后”,但我如何设置代码以等待url? 异步/等待/然后飞镖/颤振 谢谢

  • 问题内容: 目前,我正在尝试在类构造函数中使用。这样一来,我就可以为正在从事的Electron项目获取自定义标签。 但是,目前该项目无法正常工作,并出现以下错误: 有没有办法避免这种情况,以便我可以在其中使用异步/等待?而不需要回调或.then()? 问题答案: 这 永远 行不通。 该关键字允许在标记为函数中使用,但它也是功能转换成一个承诺发生器。因此,标有的函数将返回承诺。另一方面,构造函数返回

  • 我试图在react/electron项目中使用async/await,但它不起作用。我想要的是获取docker容器状态列表。但是安慰。日志(列表)返回未定义的。 有人能帮我吗?:)

  • 问题内容: 我知道这个问题以前曾被问过,但是所有解决方案都不适合我。 我有一个将参数发送到API的函数,并以列表的形式返回数据。我有一个UITableView设置为使用该列表,但是它在列表分配给变量之前运行。 码: 如果不立即将其作为重复投票,我将不胜感激,这是我尝试的方法。 派遣组 信号量计时 运行变量 其中包括= self和= self 。 编辑:要求提取项目, 问题答案: 您不能-也不应该-

  • 我试图为从服务调用异步函数的函数编写测试,但我一辈子都不知道如何让Jasmine在执行expect函数之前等待异步操作完成。 我试图使用Jasmine的“完成”功能,但我不知道如何实现它。 在本例中,只要 调用时,它立即跳转到expect并失败,因为异步操作尚未完成。

  • 问题内容: 我的代码在javascript中看起来像这样: 在完成所有这些异步调用之后,我想计算所有数组的最小值。 我要如何等待所有人? 我现在唯一的想法是拥有一个名为done的布尔数组,并在第i个回调函数中将done [i]设置为true,然后说while(不是全部都完成了){} 编辑:我想一个可能但很丑陋的解决方案是在每个回调中编辑完了的数组,然后如果每个回调中都设置了所有其他完成,则调用一个