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

Roh*_*jam 13 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;
  }
}
Run Code Online (Sandbox Code Playgroud)

请参阅上面的代码.在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;
}
Run Code Online (Sandbox Code Playgroud)

JLR*_*she 29

正如其名称所暗示的那样,await关键字将导致函数"等待",直到其承诺在执行下一行之前解析.

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

await并且async只是承诺之上的语法糖.它们允许您编写看起来很像普通同步代码的代码,即使它使用了承诺.如果我们将您的示例转换为明确使用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;
    });
}
Run Code Online (Sandbox Code Playgroud)

正如我们在这里看到的那样,该await行在一个let result = 2 + 2;处理程序中,这意味着它.then()在解决之前不会执行.使用时也一样myAPICall().await只是await为你抽象而已.

要记住的一件事(我认为你要找的点)是你不必.then()马上使用.如果您编写了这样的函数,那么您可以立即执行您的await行:

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

    // wait now
    let data = await dataP;

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

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

myAsyncFunction();
Run Code Online (Sandbox Code Playgroud)

经过一些澄清后,我可以看到你真正想知道的是如何避免必须逐个等待两个异步操作,而是让它们并行执行.实际上,如果你一个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');

    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();
Run Code Online (Sandbox Code Playgroud)

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

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();
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用await一些数组分解:

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();
Run Code Online (Sandbox Code Playgroud)

  • @RohailNajam是的,这是正确的.我已经修改了我的答案,以展示如何使用数组分解将其拆分为各自的值. (2认同)