javascript 为什么在await之后的代码没有立即运行?它不是应该是非阻塞的吗?

zyfwsgd6  于 2023-02-07  发布在  Java
关注(0)|答案(1)|浏览(590)

我很难理解async和wait在幕后是如何工作的。我知道我们有承诺,通过使用“then”函数,我们可以将所有需要做的工作放在承诺解决后,使我们的非阻塞代码。而我们希望并行执行的工作,承诺我们只是在我们的then函数之外编写它。因此,代码变得非阻塞。然而,我不知道我不明白asyncawait如何生成非阻塞代码。

async function myAsyncFunction() {
  try {
    let data = await myAPICall('https://jsonplaceholder.typicode.com/posts/1');
    // It will not run this line until it resolves await.
    let result = 2 + 2;
    return data;
  }catch (ex){
    return ex;
  }
}

请看上面的代码。在API调用被解决之前,我无法继续前进。如果它使我的代码阻塞代码,它比承诺好到哪里去了?或者我错过了asyncawait的什么东西?我应该把不依赖于await调用的代码放在哪里?这样它就可以继续工作,而不必等待执行?
我正在添加一个Promise代码,我想在一个异步等待示例中复制它。

function myPromiseAPI() {
  myAPICall('https://jsonplaceholder.typicode.com/posts/1')
    .then(function (data) {
        // data
    });
   // runs parallel
  let result = 2 + 2;
}
lp0sw83n

lp0sw83n1#

顾名思义,await关键字将导致函数“等待”,直到对应的promise解析后才执行下一行,await的全部意义在于提供一种方法,等待异步操作完成后再继续。
这段代码与阻塞代码的区别在于,当函数等待异步操作完成时,函数“外部”的世界可以继续执行。
asyncawait只是promise之上的语法糖。它们允许您编写看起来很像普通同步代码的代码,即使它在幕后使用了promise。如果我们将您的示例转换为显式使用promise的代码,则如下所示:

function myAsyncFunction() {
  return myAPICall('https://jsonplaceholder.typicode.com/posts/1')
    .then(function (data) {
       let result = 2 + 2;
       return data;
    })
    .catch(function (ex) {
        return ex;
    });
}

正如我们在这里所看到的,let result = 2 + 2;行在.then()处理程序中,这意味着在myAPICall()解析之前,它不会执行。当你使用await时也是如此。await只是为你抽象了.then()
有一点需要记住(我认为这也是你要找的),你不必马上使用await,如果你这样写函数,你可以马上执行let result = 2 + 2;行:

const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');

    // just starting the API call and storing the promise for now. not waiting yet
    let dataP = myAPICall('https://jsonplaceholder.typicode.com/posts/1');

    let result = 2 + 2;

    // Executes right away
    console.log('result', result);

    // wait now
    let data = await dataP;

    // Executes after one second
    console.log('data', data);

    return data;
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();

经过一些澄清之后,我可以看出您真正想知道的是如何避免一个接一个地等待两个异步操作,而是让它们并行执行。实际上,如果您相继使用一个await,则第二个操作将在第一个操作完成之后才开始执行:

const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');

    let data1 = await myAPICall('https://jsonplaceholder.typicode.com/posts/1');
    // logs after one second
    console.log('data1', data1);

    let data2 = await myAPICall('https://jsonplaceholder.typicode.com/posts/2');
    // logs after one more second
    console.log('data2', data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();

为了避免这种情况,你可以做的是 * 启动 * 两个异步操作,执行它们而不等待它们,将它们的承诺赋给一些变量,然后你可以等待这两个承诺:

const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');
    // both lines execute right away
    let dataP1 = myAPICall('https://jsonplaceholder.typicode.com/posts/1');
    let dataP2 = myAPICall('https://jsonplaceholder.typicode.com/posts/2');

    let data1 = await dataP1;
    let data2 = await dataP2;

    // logs after one second
    console.log('data1', data1);
    console.log('data2', data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();

另一种方法是使用Promise.all()并进行一些数组分解:

const timeout = 
    seconds => new Promise(res => setTimeout(res, seconds * 1000));

function myAPICall() {
  // simulate 1 second wait time
  return timeout(1).then(() => 'success');
}

async function myAsyncFunction() {
  try {
    console.log('starting');

    // both myAPICall invocations execute right away
    const [data1, data2] = await Promise.all([
        myAPICall('https://jsonplaceholder.typicode.com/posts/1'), 
        myAPICall('https://jsonplaceholder.typicode.com/posts/2'),
    ]);

    // logs after one second
    console.log('data1', data1);
    console.log('data2', data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();

相关问题