异步等待函数的奇怪行为

时间:2018-02-07 17:48:34

标签: javascript function asynchronous es6-promise

我有以下异步代码示例:

// 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);                
    }    
}

以下是运行separatley test1()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

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

(上面的例子非常抽象,但是#34;我发现这种行为&#34;在调用ajax请求时(而不是for-loopconsole.log('A: '+ i);)哪个序列在我的应用中非常重要(请求console.log('B: '+ i);必须在请求之前A1 ...))

2 个答案:

答案 0 :(得分:2)

<强> TEST2:

你的test2在异步之前不是异步的。你在test2.they中编写了同步代码,它们是console.log。只有test2中的异步代码才能调用promise.Let将其分解

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

上面的代码按顺序触发someWrapper()5次。然后编写第一个 sync 代码 console.log('A'+i) 5次在控制台中连续。

然后每个 someWrapper()等待 async 承诺返回并行。在每个承诺解决后,它会打印出“内部承诺” ”。 直到承诺结算,执行停止,无法进入下一步

然后,在解析承诺后,它会在控制台

中输出第二个 sync 代码 console.log('B'+i)

<强> TEST1:

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);
    }    
}

主要区别在于您 awaiting inside for loop 。所以这将 pause loop ,而 test1

不是这种情况>

因此,对于每次迭代,它都会打印 console.log('A'+i)

然后暂停 await getSomePromise()

的迭代

当承诺返回时会打印'Inside Promise'

然后打印 console.log('B'+i)

然后继续下一次迭代。

答案 1 :(得分:2)

查看评论

  

@HMR - 嗯...我不明白 - 在问题的例子中有异步   函数someWrapper()但该函数不返回任何东西(它   甚至没有退货声明(!)) - 你能解释一下你是什么   是async functions immediately return a promise的意思? - Kamil Kielczewski

似乎你不理解异步等待。我通常会建议人们等待,直到你明白承诺。但是,在下一个有问题的评论中,我给出了答案:

  

someWrapper将立即返回解析为的承诺   未定义。等待只在someWrapper函数中“等待”,但是   函数调用someWrapper会立即收到一个承诺   解决方案未定义。如果不这样做,函数总会返回一些东西   在代码中,它将返回undefined。如果它是异步功能   没有回报然后它将返回一个解决的承诺   undefined - HMR。

Await是承诺的语法糖(更好看的代码),实际上并没有等待任何事情。

以下代码可能会清除:

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);

如果你不明白为什么那段代码的输出是:

  

外部测试我们不等任何Promise {&lt;待定&gt;}

     

等待后

然后我建议你只使用承诺,直到你这样做。