【问题标题】:Why can't I move "await" to other parts of my code?为什么我不能将“等待”移动到代码的其他部分?
【发布时间】:2019-04-05 22:06:01
【问题描述】:

Edit2:底部的解决方案

我正在使用 chrome-console 并且我正在尝试输出获取的数据,并且我只能通过在正确的位置写入“await”来获得所需的输出,即使另一个解决方案可以更早地做到这一点而且我没有知道它为什么/如何工作。

solution() 是我正在做的网络课程的“官方”解决方案。 目前两个函数返回相同。 在 myFunction 中,我尝试在每个使用的函数前面写“await”,并使每个函数“异步”,但我仍然无法替换日志中的“await” ,即使其他解决方案可以。

const urls = ['https://jsonplaceholder.typicode.com/users']

const myFunction = async function() {
                                          // tried await before urls/fetch (+ make it async)
   const arrfetched = urls.map(  url => fetch(url) );   
   const [ users ] = arrfetched.map( async fetched => {  //tried await in front of arrfetched
       return (await fetched).json();                   //tried await right after return
   });
   console.log('users', await users);                   // but can't get rid of this await
}

const solution = async function() {

  const [ users ] = await Promise.all(urls.map(async function(url) {
      const response = await fetch(url);
      return response.json();
  }));
  console.log('users', users);                          // none here, so it can be done 
}

solution();
myFunction();

我认为“等待”的工作方式是:

   const a = await b;
   console.log(a);       // this doesn't work

   const a = b;
   console.log(await a); // this works

但它没有,我不明白为什么不。我觉得 Promise.all 做了一些意想不到的事情,因为简单地在声明中写“等待”不能做同样的事情,只有在声明之后。

Edit1:这不起作用

const myFunction = async function() {

    const arrfetched = await urls.map( async url => await fetch(url) );
    const [ users ] = await arrfetched.map( async fetched => {
        return await (await fetched).json();
    });
    console.log('users', users);
}

Edit2: 感谢大家的帮助,我尝试将“.toString()”放在很多变量上,并切换我在代码中放置“await”的位置哪里没有。 据我了解,如果我不使用 Promise.all,那么每次我想使用(如在实际数据中,而不仅仅是使用)具有承诺的函数或变量时,我都需要等待强>。仅在正在处理数据的地方等待而不进一步向上是不够的。 在上面的 Edit1 中,用户在任何其他等待完成之前运行,因此无论我写了多少等待,都没有执行。在(在我的情况下是 chrome-)控制台中复制此代码可以很好地演示它:

const urls = [
      'https://jsonplaceholder.typicode.com/users',
    ]
    const myFunction = async function() {

      const arrfetched =  urls.map( async url => fetch(url) );
      const [ users ] =  arrfetched.map( async fetched => {
          console.log('fetched', fetched);
          console.log('fetched wait', await fetched);
          return (await fetched).json();
      });
      console.log('users', users);
      console.log('users wait', await users);
    }

    myFunction();

// Output in the order below:
// fetched()
// users()
// fetched wait()
// users wait()

【问题讨论】:

  • 不清楚你想要达到什么目的。
  • 我想像这样摆脱 myFunction 控制台中的等待:console.log('users', users);
  • 你在这里让事情变得过于复杂。在您的“edit1”中,您正在使用async await 解析一组承诺,然后,您将该数组映射为实际上假装将await 加倍已经解决的问题。如果fetch 返回Promise,则first .map 应该是异步的。如果.json() 返回Promise,那么第二个也应该是异步的。然而,真正的await 应该发生在fetch 操作上,而不是其他任何事情上。
  • 那么等待比必要的更多会破坏其他工作代码吗?
  • 只是为了澄清这一点(除了我的回复):额外的await 永远不会有害(除了性能方面)。等待一个非承诺,例如await 'hello' 会先把它变成一个 Promise 然后等待它,所以它等价于 await Promise.resolve('hello')

标签: javascript promise async-await


【解决方案1】:

TL; DR:Promise.all 在那里很重要,但没什么神奇的。它只是将一个 Promise 数组转换为一个用数组解析的 Promise。

让我们分解myFunction

const arrfetched = urls.map(  url => fetch(url) );

这会返回一个 Promise 数组,到目前为止一切正常。


const [ users] = arrfetched.map( async fetched => {
  return (await fetched).json();
});

你正在解构一个数组来获取第一个成员,所以它和这个是一样的:

const arr = arrfetched.map( async fetched => {
  return (await fetched).json();
});
const users = arr[0];

在这里,我们将一组 Promise 转换为另一个 Promise 数组。请注意,使用 async 函数调用 map 总是会产生一个 Promise 数组。

然后将该数组的第一个成员移动到users,因此users 现在实际上包含一个Promise。然后在打印之前等待它:

console.log('users', await users);

相比之下,另一个 sn-p 在这里做的事情略有不同:

const [ users ] = await Promise.all(urls.map(async function(url) {
  const response = await fetch(url);
  return response.json();
}));

再一次,让我们分离解构:

const arr = await Promise.all(urls.map(async function(url) {
  const response = await fetch(url);
  return response.json();
}));
const users = arr[0];

Promise.all 将 Promise 数组转换为单个 Promise,从而生成一个数组。这意味着,在await Promise.all 之后,arr 中的所有内容都已等待(您可以将await Promise.all 想象成一个等待数组中所有内容的循环)。这意味着 arr 只是一个普通数组(不是 Promises 数组),因此 users 已经在等待,或者更确切地说,它从一开始就不是 Promise,因此您不需要 @987654339 @它。

【讨论】:

  • 在这里,我们将一组 Promise 转换为另一个 Promise 数组。请注意,使用 async 函数调用 map 总是会产生一个 Promises 数组。 哦,所以我的 Edit1: const [ users] = await arrfetched.map( ... 不会等待 pormises,而是承诺,它不必等待!
  • 完全正确。 await [Promise.resolve(42), Promise.resolve(24)] == [Promise.resolve(42), Promise.resolve(24)](因为你在等待一个数组,它不是 Promise,因此什么也不做),但是 await Promise.all([Promise.resolve(42), Promise.resolve(24)]) == [await Promise.resolve(42), await Promise.resolve(24)] == [42, 24]
【解决方案2】:

也许解释这一点的最简单方法是分解每个步骤实现的目标:

const urls = ['https://jsonplaceholder.typicode.com/users']

async function myFunction() {

  // You can definitely use `map` to `fetch` the urls
  // but remember that `fetch` is a method that returns a promise
  // so you'll just be left with an array filled with promises that
  // are waiting to be resolved.
  const arrfetched = urls.map(url => fetch(url));

  // `Promise.all` is the most convenient way to wait til everything's resolved
  // and it _also_ returns a promise. We can use `await` to wait for that 
  // to complete.
  const responses = await Promise.all(arrfetched);

  // We now have an array of resolved promises, and we can, again, use `map`
  // to iterate over them to return JSON. `json()` _also_ returns a promise
  // so again you'll be left with an array of unresolved promises...
  const userData = responses.map(fetched => fetched.json());

  //...so we wait for those too, and destructure out the first array element
  const [users] = await Promise.all(userData);

  //... et voila!
  console.log(users);
}

myFunction();

【讨论】:

    【解决方案3】:

    Await 只能在异步函数中使用。 Await 是一个保留键。如果它不是异步的,你就不能等待。这就是为什么它在 console.log 中有效,但在全局范围内无效。

    【讨论】:

    • 所以当我在 Edit1 中编写类似的东西时,它不起作用,因为即使我没有收到错误,某些东西也不是异步的?
    • 让我重新表述一下。 await 键需要在异步函数中使用。 map 函数也是一个会在可能的情况下执行的函数。如果你需要这些数据,你可以在 promise.all 中映射这些调用。这样,只有在所有承诺都得到解决后,该功能才会继续
    • 因此,通过在 console.log 中写入 await,我得到的结果与 await Promise.all 相同,但是当我在变量声明中写入 await 时,它会被忽略,因为它不在异步函数中?
    • 是的,但它看起来像一个错误。你应该尽量避免这种情况。如果你想等待。对于 Promise,请使用正确的函数。希望这有助于逻辑,因为它可以非常抽象。
    猜你喜欢
    • 2021-08-14
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 2019-12-18
    • 2019-09-24
    • 1970-01-01
    • 1970-01-01
    • 2014-10-07
    相关资源
    最近更新 更多