【问题标题】:JavaScript Async/Await: Unsuccessful with attempts to modify working codeJavaScript Async/Await:尝试修改工作代码失败
【发布时间】:2020-09-06 10:17:56
【问题描述】:

我使用 Async/Await 编写了一个简短的脚本,它会在很短的时间间隔后一个一个地打印出字母。根据我所了解的情况,我尝试以多种方式重写代码,期望得到相同的结果,但我无法使这些替代方案中的任何一个起作用。特别是,我认为更改代码中 console.log() 发生的位置会很简单。

这是原始的工作代码:

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

// Promisify setTimeout() and feed in counter from sendMessage()
  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(resolve, timer[num]);
    })
  };

// Async/Await with a For loop calling setTimeoutPromise()
  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
      console.log(message[count]);
    };
  };

  sendMessage();

}

welcomeMessage();

然后我尝试进行一些修改,但都没有奏效。

Mdofication #1:在这个版本中,我认为我可以直接调用并运行 sendMessage() 函数中的代码,而无需稍后调用它。但是,修改后什么都没有发生:

async () => { //No name and removed call to sendMessage() later in code
  for (count = 0; count < message.length; count++) {
    await setTimeoutPromise(count);
    console.log(message[count]);
  };
};

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

// Promisify setTimeout() and feed in counter from sendMessage()
  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(resolve, timer[num]);
    })
  };

  async () => { //No name and removed call to sendMessage() later in code
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
      console.log(message[count]);
    };
  };
}

welcomeMessage();

修改 #2:我还原了代码,然后尝试将 console.log() 函数移动到 setTimeout() 函数中,认为这将在每个循环中调用。使用空 () 和 (resolve) 都被传递到 setTimeout(),它只打印第一个字母。使用 (resolve, num) 表示未定义:

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout((resolve) => {
          console.log(message[num]);
          resolve;
      }, timer[num]);
    })
  };

  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  };

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout((resolve) => {
          console.log(message[num]);
          resolve;
      }, timer[num]);
    })
  };

  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  };

  sendMessage();

}

welcomeMessage();

修改#3:最后,我尝试提前定义一个函数以传递给 setTimeout(),该函数将用于处理“resolve”和 console.log()。我尝试了一些变体,但似乎并没有在循环中进行,因为 console.log() 只被调用了一次。

  // New function to handle resolve and the counter
  function newFunction(func, num) {
    console.log(message[num]);
    func;
  }

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(newFunction(resolve, num), timer[num]);
    })
  };

  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  };

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

  // New function to handle resolve and the counter
  function newFunction(func, num) {
    console.log(message[num]);
    func;
  }

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(newFunction(resolve, num), timer[num]);
    })
  };

  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  };
  
  sendMessage()

}

welcomeMessage();

【问题讨论】:

  • func; 不是函数调用(与 setTimeout(…) 等现有函数调用相比——它需要括号)。 async () =&gt; {} 是一个函数表达式,也缺少一个调用。见stackoverflow.com/questions/8228281/…
  • resolve; 有同样的问题。应该是resolve()。在setTimeout(newFunction(resolve, num), timer[num]),关于setTimeout的正确使用,见stackoverflow.com/questions/7137401/…
  • 在最后的代码中你有错误你调用函数 newFunction 并且什么都不传递给 setTimeout 你需要编写返回函数的函数或将它包装内联setTimeout(() =&gt; newFunction(resolve, num), timer[num]); 并且你需要调用该函数func
  • 感谢 Ry- 的回复和有用的链接。我能够让代码运行,并对我的代码的含义有了更多的了解。 @jcubic,也感谢您的解释。

标签: javascript asynchronous


【解决方案1】:

在我看来,您在深入了解同步 JavaScript 的工作原理之前就已经开始使用异步了。异步本身也已经够难了,所以再加上它,它会让你完全糊涂。

让我解释一下你的 sn-ps 发生了什么以及有什么问题。


让我们从工作的开始吧。

那个代码:

const setTimeoutPromise = num => {
  return new Promise(resolve => {
    setTimeout(resolve, timer[num]);
  })
};

...创建一个名为setTimeoutPromise 的函数,即:

  • 将索引(数字)作为参数
  • 返回一个承诺:
    • timer[num] 毫秒后
    • 解析为undefinedsetTimeout 默认不向其回调传递任何内容;在这种情况下,回调是resolve 函数)

下一部分:

const sendMessage = async () => {
  for (count = 0; count < message.length; count++) {
    await setTimeoutPromise(count);
    console.log(message[count]);
  };
};

...定义了一个名为 sendMessage 的异步函数,即:

  • 迭代message,为每个字符:
    • 调用setTimeoutPromise 并等待它返回的承诺
    • 等待后,将当前字符记录到控制台

最后,

sendMessage();

...调用sendMessage,因此开始输入。


现在,让我们继续下一个 sn-p。

这段代码:

async () => { //No name and removed call to sendMessage() later in code
  for (count = 0; count < message.length; count++) {
    await setTimeoutPromise(count);
    console.log(message[count]);
  };
};

...创建一个异步函数,但它不会调用或将其分配给任何变量:只是将其丢弃。

要修复此 sn-p,请在其后添加 () 立即调用该函数!

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

// Promisify setTimeout() and feed in counter from sendMessage()
  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(resolve, timer[num]);
    })
  };

  (async () => { //No name and removed call to sendMessage() later in code
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
      console.log(message[count]);
    };
  })(); //The () at the end calls it
}

welcomeMessage();

有问题的 sn-p #2

这有两个问题:

const setTimeoutPromise = num => {
  return new Promise(resolve => {
    setTimeout((resolve) => { //Problem 1
        console.log(message[num]);
        resolve; //Problem 2
    }, timer[num]);
  })
};
  1. 您尝试从setTimeout 中获取一个名为resolve 的参数,但正如我上面提到的,它没有通过任何参数。

    要解决它,请从 setTimeout((resolve) =&gt; { 中删除 resolve!由于词法作用域,我们已经有了上述行中的resolve 函数。

  2. 您不调用resolve,这会使awaiting 代码在第一个字母之后挂起(承诺永远不会得到解决)。

    要修复它,请将() 放在resolve 之后!

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(() => {
          console.log(message[num]);
          resolve();
      }, timer[num]);
    })
  };

  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  };

  sendMessage();

}

welcomeMessage();

有问题的 sn-p #3

这段代码也有两个问题:

// New function to handle resolve and the counter
function newFunction(func, num) {
  console.log(message[num]);
  func; //Problem 1
}
 const setTimeoutPromise = num => {
  return new Promise(resolve => {
    setTimeout(newFunction(resolve, num), timer[num]); //Problem 2
  })
};
  1. 同上; newFunction 不调用 resolve(命名为 fn)。

    当你打算调用一个函数时,尽量不要忘记()

  2. 这与问题 1 正好相反。您立即调用newFunction(由于它后面的括号:(resolve, num)),并将其返回值undefined)传递给@987654356 @。如果没有问题 1,这将导致立即记录所有字母。

    在这种情况下,让setTimeout 在内部调用该函数,方法是在其后删除(resolve, num)。要将参数传递给它,setTimeout 接受额外的参数,它将移交给它的回调(在本例中为 newFunction)。

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

  // New function to handle resolve and the counter
  function newFunction(func, num) {
    console.log(message[num]);
    func();
  }

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(newFunction, timer[num], resolve, num);
    })
  };

  const sendMessage = async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  };
  
  sendMessage()

}

welcomeMessage();

大家一起...

可以将这些修复结合起来,得到类似的东西:

const welcomeMessage = () => {
  
  const message = 'hello'
  const timer = [200,400,200,400,200,400];

  // New function to handle resolve and the counter
  function newFunction(func, num) {
    console.log(message[num]);
    func();
  }

  const setTimeoutPromise = num => {
    return new Promise(resolve => {
      setTimeout(newFunction, timer[num], resolve, num);
    })
  };

  (async () => {
    for (count = 0; count < message.length; count++) {
      await setTimeoutPromise(count);
    };
  })();

}

welcomeMessage();

结论

使用括号 (()) 调用函数,但避免将函数用作对象:将其传递或分配给某物,获取或设置其属性等。

【讨论】:

  • 难以置信的答案。谢谢。在接下来的几天里,我会回到这个,以确保我完全消化了这个,并做一些后续阅读和修补。第一次在网站上发布问题 - 在此之后会被宠坏。
  • @UnderwaterHandshake 我很高兴能提供帮助。您的问题在这里是一个相对较好的问题(只需阅读标记为 JavaScript 的 10 个最新问题并与您的问题进行比较),尤其是作为第一个问题。我认为好的问题应该得到好的答案。还有...欢迎来到 SO!
  • 我一直在重读答案,我很难理解的一点是片段#3 -> 你的观点#2。您指出我会立即调用newFunction 并返回undefined,这将导致所有信件同时记录。我相信我自己也遇到过这种情况,但我不明白为什么。我看到两个潜在的原因:
  • 这是因为你基本上取消了setTimeout的效果。就像你写const returnValue = newFunction(resolve, num); setTimeout(returnValue, timer[num]);一样,其中retrunValueundefined
  • 我写过在这种情况下会发生什么in one of my older answers。这是一个常见的错误,几乎每个 JS 新手都会犯这种错误。 3年前,我犯了同样的错误,不明白为什么它不起作用......
猜你喜欢
  • 2018-12-15
  • 2021-11-29
  • 2021-12-18
  • 1970-01-01
  • 2022-11-03
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
相关资源
最近更新 更多