很酷的问题。
你说得对,它们都是异步代码。
作为差异的简单答案。如果你正在做类似的事情:
const fetchUser = async () => {
const result = await fetch("/user");
return await result.json();
}
async main1() {
setTimeout(() => console.log("done", 2000));
}
async main2() {
await fetchUser();
console.log("done");
}
如果你没有在其他地方阻塞线程,setTimeout 在它记录“完成”之前总是需要大约 2000 毫秒。当 API 完成时,fetchUser 将记录“完成”,可能是 100 毫秒,也可能是 10000 毫秒。
但区别远不止于此:
这部分与回调风格的代码和承诺风格的代码的区别有关。
回调风格是一种较旧的编码方式,这里的区别不止于此。
让我们暂时搁置 setTimeout 并讨论两种可能进行 fetch 调用的方法。
const fetchUserOne = async() => {
const result = await fetch('https://jsonplaceholder.typicode.com/todos/1');
const json = await result.json();
return json;
}
const fetchUserTwo = () => {
return fetch('https://jsonplaceholder.typicode.com/todos/2')
.then(response => response.json())
};
async function main() {
const result1 = fetchUserOne();
const result2 = fetchUserTwo();
console.log(result1);
console.log(result2)
const awaitedResult1 = await result1;
const awaitedResult2 = await result2;
console.log(awaitedResult1);
console.log(awaitedResult2);
}
main().then(console.log("complete"));
现在我想在这里强调的是,虽然第二个示例使用了回调样式 - 它们都使用了 Promise。
当您运行代码时(按 F12 查看完整的对象),您会注意到 result1 和 result2 的日志是承诺。
Window.setTimeout 另一方面不使用 Promise。
const result = setTimeout(() => {
console.log("done");
}, 2000);
console.log(result);
setTimeout的返回值是一个数字,which can be used to cancel the timeout.
这给我们带来了主要区别:
Promise 不可取消,setTimeout 是
See this Stack Overflow question about cancelling a promise.
为了展示一个例子,让我们修改上面的例子。
const fetchUser = async () => {
const result = await fetch("https://jsonplaceholder.typicode.com/todos/1");
return await result.json();
}
let timeout;
async function main1() {
console.log("start main1");
timeout = setTimeout(() => console.log("done timeout"), 2000);
}
async function main2() {
console.log("start main2");
await fetchUser();
console.log("done fetchuser");
}
main1();
main2();
clearTimeout(timeout);
在上面,我们可以看到我们可以很容易地中止超时调用,而我们不能直接取消承诺。
这并不是说你不能取消那个获取请求,as you can see in this thread,而是你不能取消承诺本身。