为什么等待后的代码不会马上运行?它不应该是非阻塞的吗?

时间:2017-04-09 02:58:27

标签: javascript async-await es6-promise ecmascript-2017

大家好我很难理解异步和等待在幕后工作的方式。我知道我们有通过使用“then”函数制作非阻塞代码的promise,我们可以在promise解决后放置我们需要做的所有工作。我们希望做的工作与我们希望并行,我们只需将它写在我们的函数之外。因此代码变得非阻塞。但是,我不明白async await如何制作非阻止代码。

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调用解决之前,我无法继续前进。如果它使我的代码阻止代码,那么它比promises更好吗?或者我错过了关于asyncawait的内容吗?我在哪里放置不依赖于等待调用的代码?所以它可以继续工作而不等待执行?

我正在添加一个Promise代码,我希望在async await示例中进行复制。

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

1 个答案:

答案 0 :(得分:25)

正如其名称所暗示的那样,await关键字将导致该功能等待"等待"直到它的承诺在执行下一行之前解决。

这个和阻塞代码之间的区别在于,当函数等待异步操作完成时,函数将继续执行 outside 函数。

asyncawait只是承诺之上的语法糖。它们允许您编写看起来很像普通同步代码的代码,即使它使用了承诺。如果我们将您的示例转换为明确使用promises的内容,它将类似于:

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;行:



function myAPICall() {
  // simulate 1 second wait time
  return new Promise(resolve => setTimeout(resolve, 1000))
    .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);

    let data = await dataP;

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

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

myAsyncFunction();




经过一些澄清后,我可以看到你真正想知道的是如何避免必须逐个等待两个异步操作,而是让它们并行执行。实际上,如果你在另一个之后使用一个await,那么第二个不会开始执行,直到第一个完成:



function myAPICall() {
  // simulate 1 second wait time
  return new Promise(resolve => setTimeout(resolve, 1000))
    .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);

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

myAsyncFunction();




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



function myAPICall() {
  // simulate 1 second wait time
  return new Promise(resolve => setTimeout(resolve, 1000))
    .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);
    console.log(data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();




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



function myAPICall() {
  // simulate 1 second wait time
  console.log('myAPICall called');
  return new Promise(resolve => setTimeout(resolve, 1000))
    .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);
    console.log(data2);
  } catch (ex) {
    return ex;
  }
}

myAsyncFunction();