没有 async/wait 的承诺。有人可以告诉我另一种方法来解决这个问题吗?
Promises without async/wait. Can somebody show me another way to resolve this problem?
我需要构建一个显示 2 个数组的对象。为此,我调用了第一个承诺,然后我使用它的结果调用了第二个承诺。
我想知道是否有解决此问题的最佳方法。
问题描述如下。
/**
* DO NOT USE ASYNC/AWAIT
* Using the below two functions produce the following output
* {
* authors: ['bob', 'sally'],
* titles: ['Greeting the World', 'Hello World!']
* }
* */
const getBooks = () => {
return new Promise((resolve) => {
resolve([
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]);
});
};
const getTitle = (bookId) => {
return new Promise((resolve, reject) => {
switch (bookId) {
case 1:
resolve({ title: "Greeting the World" });
break;
case 2:
resolve({ title: "Hello World!" });
break;
default:
reject(new Error("404 - book not found"));
}
});
};
let authors = {authors: [], titles: []}
getBooks()
.then(result => {
result.map(
t => {
authors.authors.push(t.author)
getTitle(t.bookId)
.then(result => {
authors.titles.push(result.title)
})
})
}).then(_ => console.log(authors))
您的代码仅 恰好 产生所需的结果,因为 Promise 构造函数 运行 是同步的。如果这是真的 API 并且值没有完全同步检索,您的代码将无法工作:
/**
* DO NOT USE ASYNC/AWAIT
* Using the below two functions produce the following output
* {
* authors: ['bob', 'sally'],
* titles: ['Greeting the World', 'Hello World!']
* }
* */
const getBooks = () => {
return new Promise((resolve) => {
resolve([
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]);
});
};
const getTitle = (bookId) => {
return new Promise((resolve, reject) => {
switch (bookId) {
case 1:
setTimeout(() => { resolve({ title: "Greeting the World" }) });
break;
case 2:
resolve({ title: "Hello World!" });
break;
default:
reject(new Error("404 - book not found"));
}
});
};
let authors = {authors: [], titles: []}
getBooks()
.then(result => {
result.map(
t => {
authors.authors.push(t.author)
getTitle(t.bookId)
.then(result => {
authors.titles.push(result.title)
})
})
}).then(_ => console.log(authors))
要修复它,请使用 Promise.all
等待映射的 Promise 数组解析为您需要的字符串:
const getBooks=()=>new Promise(o=>{o([{bookId:1,author:"bob"},{bookId:2,author:"sally"}])}),getTitle=o=>new Promise((e,t)=>{switch(o){case 1:e({title:"Greeting the World"});break;case 2:e({title:"Hello World!"});break;default:t(new Error("404 - book not found"))}});
getBooks()
.then(result => Promise.all(result.map(
obj => Promise.all([
obj, // pass the bookId / author along to the next `.then`
getTitle(obj.bookId) // retrieve the title for this book
])
)))
.then((resultsWithTitles) => {
const authors = resultsWithTitles.map(([obj]) => obj.author);
const titles = resultsWithTitles.map(([, titleObj]) => titleObj.title);
console.log({ authors, titles });
})
// if this was a true API, you'd want to catch possible errors here
使用 Promise.all
获取所有书籍中的 title
:
let authors = { authors: [], titles: [] }
getBooks()
.then(books => {
const promises = books.map(book => {
authors.authors.push(book.author)
getTitle(book.bookId)
.then(({ title }) => {
authors.titles.push(title)
});
});
return Promise.all(promises);
}).then(_ => console.log(authors))
我的建议是使用 async/await
来完成类似的任务。你的代码会变成这样:
const authors = { authors: [], titles: [] }
const books = await getBooks()
for (const book of books) {
const { title } = await getTitle(book.bookId)
authors.authors.push(book.author)
authors.titles.push(title)
}
console.log(authors);
承诺陷阱
看看你是如何定义 authors
before 你的 Promise 序列的?这是新手做的most common mistake
这是一种方法,您可以通过对 then
调用进行排序 -
const getAuthors = () =>
getBooks()
.then(r => r.map(appendTitle))
.then(r => Promise.all(r))
.then(r => ({
authors: r.map(b => b.author),
titles: r.map(b => b.title)
}))
const appendTitle = b =>
getTitle(b.bookId)
.then(r => Object.assign(b,r))
getAuthors ()
.then(console.log, console.error)
{
"authors": [
"bob",
"sally"
],
"titles": [
"Greeting the World",
"Hello World!"
]
}
展开下面的代码片段以在您自己的浏览器中验证结果 -
const getBooks = () => {
return new Promise((resolve) => {
resolve([
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]);
});
};
const getTitle = (bookId) => {
return new Promise((resolve, reject) => {
switch (bookId) {
case 1:
resolve({ title: "Greeting the World" });
break;
case 2:
resolve({ title: "Hello World!" });
break;
default:
reject(new Error("404 - book not found"));
}
});
};
const appendTitle = b =>
getTitle(b.bookId)
.then(r => Object.assign(b,r))
const getAuthors = () =>
getBooks()
.then(r => r.map(appendTitle))
.then(r => Promise.all(r))
.then(r => ({
authors: r.map(b => b.author),
titles: r.map(b => b.title)
}))
getAuthors ().then(console.log, console.error)
改进 getBooks 和 getTitle
因为 getBooks
和 getTitle
是简单的同步函数,我认为使用带有执行函数的 Promise 是对 Promises 的滥用。我们可以将它们重写得更简单 -
const getBooks = () =>
Promise.resolve(BOOKS)
const getTitle = (bookId) =>
{ if (bookId in TITLES)
return Promise.resolve({ title: TITLES[bookId] })
else
return Promise.reject(new Error("404 - book not found"))
}
其中BOOKS
和TITLES
定义为-
const BOOKS =
[
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]
const TITLES =
{
1: "Greeting the World",
2: "Hello World!"
}
展开下面的代码片段以在您自己的浏览器中验证结果 -
const BOOKS =
[
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]
const TITLES =
{
1: "Greeting the World",
2: "Hello World!"
}
const getBooks = () =>
Promise.resolve(BOOKS)
const getTitle = (bookId) =>
{ if (bookId in TITLES)
return Promise.resolve({ title: TITLES[bookId] })
else
return Promise.reject(new Error("404 - book not found"))
}
const appendTitle = b =>
getTitle(b.bookId)
.then(r => Object.assign(b,r))
const getAuthors = () =>
getBooks()
.then(r => r.map(appendTitle))
.then(r => Promise.all(r))
.then(r => ({
authors: r.map(b => b.author),
titles: r.map(b => b.title)
}))
getAuthors ().then(console.log, console.error)
我需要构建一个显示 2 个数组的对象。为此,我调用了第一个承诺,然后我使用它的结果调用了第二个承诺。
我想知道是否有解决此问题的最佳方法。
问题描述如下。
/**
* DO NOT USE ASYNC/AWAIT
* Using the below two functions produce the following output
* {
* authors: ['bob', 'sally'],
* titles: ['Greeting the World', 'Hello World!']
* }
* */
const getBooks = () => {
return new Promise((resolve) => {
resolve([
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]);
});
};
const getTitle = (bookId) => {
return new Promise((resolve, reject) => {
switch (bookId) {
case 1:
resolve({ title: "Greeting the World" });
break;
case 2:
resolve({ title: "Hello World!" });
break;
default:
reject(new Error("404 - book not found"));
}
});
};
let authors = {authors: [], titles: []}
getBooks()
.then(result => {
result.map(
t => {
authors.authors.push(t.author)
getTitle(t.bookId)
.then(result => {
authors.titles.push(result.title)
})
})
}).then(_ => console.log(authors))
您的代码仅 恰好 产生所需的结果,因为 Promise 构造函数 运行 是同步的。如果这是真的 API 并且值没有完全同步检索,您的代码将无法工作:
/**
* DO NOT USE ASYNC/AWAIT
* Using the below two functions produce the following output
* {
* authors: ['bob', 'sally'],
* titles: ['Greeting the World', 'Hello World!']
* }
* */
const getBooks = () => {
return new Promise((resolve) => {
resolve([
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]);
});
};
const getTitle = (bookId) => {
return new Promise((resolve, reject) => {
switch (bookId) {
case 1:
setTimeout(() => { resolve({ title: "Greeting the World" }) });
break;
case 2:
resolve({ title: "Hello World!" });
break;
default:
reject(new Error("404 - book not found"));
}
});
};
let authors = {authors: [], titles: []}
getBooks()
.then(result => {
result.map(
t => {
authors.authors.push(t.author)
getTitle(t.bookId)
.then(result => {
authors.titles.push(result.title)
})
})
}).then(_ => console.log(authors))
要修复它,请使用 Promise.all
等待映射的 Promise 数组解析为您需要的字符串:
const getBooks=()=>new Promise(o=>{o([{bookId:1,author:"bob"},{bookId:2,author:"sally"}])}),getTitle=o=>new Promise((e,t)=>{switch(o){case 1:e({title:"Greeting the World"});break;case 2:e({title:"Hello World!"});break;default:t(new Error("404 - book not found"))}});
getBooks()
.then(result => Promise.all(result.map(
obj => Promise.all([
obj, // pass the bookId / author along to the next `.then`
getTitle(obj.bookId) // retrieve the title for this book
])
)))
.then((resultsWithTitles) => {
const authors = resultsWithTitles.map(([obj]) => obj.author);
const titles = resultsWithTitles.map(([, titleObj]) => titleObj.title);
console.log({ authors, titles });
})
// if this was a true API, you'd want to catch possible errors here
使用 Promise.all
获取所有书籍中的 title
:
let authors = { authors: [], titles: [] }
getBooks()
.then(books => {
const promises = books.map(book => {
authors.authors.push(book.author)
getTitle(book.bookId)
.then(({ title }) => {
authors.titles.push(title)
});
});
return Promise.all(promises);
}).then(_ => console.log(authors))
我的建议是使用 async/await
来完成类似的任务。你的代码会变成这样:
const authors = { authors: [], titles: [] }
const books = await getBooks()
for (const book of books) {
const { title } = await getTitle(book.bookId)
authors.authors.push(book.author)
authors.titles.push(title)
}
console.log(authors);
承诺陷阱
看看你是如何定义 authors
before 你的 Promise 序列的?这是新手做的most common mistake
这是一种方法,您可以通过对 then
调用进行排序 -
const getAuthors = () =>
getBooks()
.then(r => r.map(appendTitle))
.then(r => Promise.all(r))
.then(r => ({
authors: r.map(b => b.author),
titles: r.map(b => b.title)
}))
const appendTitle = b =>
getTitle(b.bookId)
.then(r => Object.assign(b,r))
getAuthors ()
.then(console.log, console.error)
{
"authors": [
"bob",
"sally"
],
"titles": [
"Greeting the World",
"Hello World!"
]
}
展开下面的代码片段以在您自己的浏览器中验证结果 -
const getBooks = () => {
return new Promise((resolve) => {
resolve([
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]);
});
};
const getTitle = (bookId) => {
return new Promise((resolve, reject) => {
switch (bookId) {
case 1:
resolve({ title: "Greeting the World" });
break;
case 2:
resolve({ title: "Hello World!" });
break;
default:
reject(new Error("404 - book not found"));
}
});
};
const appendTitle = b =>
getTitle(b.bookId)
.then(r => Object.assign(b,r))
const getAuthors = () =>
getBooks()
.then(r => r.map(appendTitle))
.then(r => Promise.all(r))
.then(r => ({
authors: r.map(b => b.author),
titles: r.map(b => b.title)
}))
getAuthors ().then(console.log, console.error)
改进 getBooks 和 getTitle
因为 getBooks
和 getTitle
是简单的同步函数,我认为使用带有执行函数的 Promise 是对 Promises 的滥用。我们可以将它们重写得更简单 -
const getBooks = () =>
Promise.resolve(BOOKS)
const getTitle = (bookId) =>
{ if (bookId in TITLES)
return Promise.resolve({ title: TITLES[bookId] })
else
return Promise.reject(new Error("404 - book not found"))
}
其中BOOKS
和TITLES
定义为-
const BOOKS =
[
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]
const TITLES =
{
1: "Greeting the World",
2: "Hello World!"
}
展开下面的代码片段以在您自己的浏览器中验证结果 -
const BOOKS =
[
{
bookId: 1,
author: "bob"
},
{
bookId: 2,
author: "sally"
}
]
const TITLES =
{
1: "Greeting the World",
2: "Hello World!"
}
const getBooks = () =>
Promise.resolve(BOOKS)
const getTitle = (bookId) =>
{ if (bookId in TITLES)
return Promise.resolve({ title: TITLES[bookId] })
else
return Promise.reject(new Error("404 - book not found"))
}
const appendTitle = b =>
getTitle(b.bookId)
.then(r => Object.assign(b,r))
const getAuthors = () =>
getBooks()
.then(r => r.map(appendTitle))
.then(r => Promise.all(r))
.then(r => ({
authors: r.map(b => b.author),
titles: r.map(b => b.title)
}))
getAuthors ().then(console.log, console.error)