在 map 内使用 Promise 时,我遇到了一些奇怪的行为。
这本身并不是一个问题,但我想了解发生了什么。
let books = [
{Name: "Moby Dick",
AuthorId: 1
},
{Name: "The Great Gatsby",
AuthorId: 2}
]
let authors = [
{AuthorId: 1,
Name: "Herman Melville"
},
{AuthorId: 2,
Name: "F. Scott Fitzgerald"
}
]
const getAuthorName = (AuthorId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(authors.find((author) => {
return author.AuthorId === AuthorId
}).Name)
}, 1000
})
}
let responseArray = []
let promises = books.map((book) => (
getAuthorName(book.AuthorId).then((res) => {
responseArray.push({
...book,
AuthorName: res
})
})
))
setTimeout(() => console.log(responseArray), 500)
//I would expect to have to do this:
//Promise.all(promises).then((res) => console.log(res))
我希望
setTimeout(() => console.log(responseArray), 5000)
记录一个空字符串,因为 Promise 数组尚未通过 Promise.all 运行,但看起来即使映射应该只是返回一个 Promise 数组,但它实际上正在运行 Promise。这是为什么?
编辑
我已经编辑了 getAuthor promise ,在决定进一步详细说明之前稍等一下,因为这不是我想要表达的重点。
我希望映射一个数组,以返回一个新数组,其中包含映射中返回的任何内容。例如,如果我这样做
let arrayOfPromises = books.map((book) => {
return getAuthor(book.AuthorId)
}
我希望 arrayOfPromises 是 getAuthor promise 的数组。
但是,当我在返回的 Promise 末尾抛出 .then() 时,.then() 中的代码似乎正在计算。
如果我这样做
let promises = books.map((book) => {
return getAuthor(book.AuthorId).then((res) => {
console.log(res)
})
}
在控制台中,我将看到“Herman Merville”和“F. Scott Fitzgerald”,在 Promise var 中,我将看到一系列 Promise。
虽然我认为每个 getAuthor 的 .then 只会在我调用 Promise.all(promises) 时进行评估,因为 getAutor promise 会在 map 内返回。我在这里理解有问题吗?
最佳答案
这是因为您的 Promise 中的代码不是异步的,因此它会立即解析,因为没有什么可等待的。
要对此进行扩展,您所做的与
相同const getAuthorName = (AuthorId) => {
return Promise.resolve(authors.find((author) => {
return author.AuthorId === AuthorId
}).Name)
}
它将允许您在函数上链接 then
语法,但这也意味着 then
将在函数调用后直接执行。
编辑
根据您的编辑,这里还有一些内容。
您已使用 setTimeout
将方法修改为异步。这意味着 map 现在按照您的预期返回一组 promise 。
但是您的代码还有另一个问题,您还将 console.log
封装在 setTimeout
中,该计时器具有更大的计时器!
为了更好地了解这里发生的事情,我强烈建议您观看 this video .
但是,本着 StackOverflow 的精神,我将在此处添加一些书面解释。
您首先创建一个 Promise 数组,在创建后大约 1 秒后执行回调(它们不会等待 map 结束)。
一旦完成,它们就会进入浏览器的事件循环。基本上,它是主线程释放后浏览器将立即处理的一堆事件。
因此,在创建后 1 秒,promise 将解析,并将其回调放在此事件循环上。
现在,当您运行 console.log
时会发生什么。
如果您没有将其放入自己的 setTimeout
中,它将打印一个空数组。
如果 setTimeout
为 500 毫秒怎么办?在这里,我们可以放心地假设 map
将花费不到 500 毫秒的时间来完成并启动新的 setTimeout
,因此 console.log
将到达 <首先是事件循环,然后再次打印一个空数组。
5秒怎么样?在到达 console.log
之前,两个 setTimeouts
都会结束,因此您将打印一个已填充的数组。
我做了一个jsfiddle如果您想亲自尝试一下。
我希望这有助于澄清问题。
关于javascript - 在映射数组时调用 Promise,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57419751/