【问题标题】:Promises without async/wait. Can somebody show me another way to resolve this problem?没有异步/等待的承诺。有人可以告诉我另一种方法来解决这个问题吗?
【发布时间】:2021-06-10 01:26:57
【问题描述】:

我需要构建一个显示 2 个数组的对象。为此,我调用第一个 Promise,然后使用它的结果调用第二个 Promise。

我想知道是否有解决此问题的最佳方法。

问题描述如下。

/**
 * 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))
      

    
 

【问题讨论】:

  • 当错误提示文本不足时,请不要再复制粘贴相同的文本。尝试以不同的方式实际解释问题。你在这里没有做任何异步的事情,所以不清楚你为什么要使用 Promises。这是应该解释的事情,而不是重复相同的文字。

标签: javascript asynchronous ecmascript-6 es6-promise event-loop


【解决方案1】:

您的代码只有恰好发生才能产生所需的结果,因为 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

【讨论】:

  • 太棒了!感谢您的帮助!
【解决方案2】:

使用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);

【讨论】:

    【解决方案3】:

    承诺陷阱

    看看你是如何定义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!"
      ]
    }
    

    展开下面的sn-p,在自己的浏览器中验证结果-

    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

    因为getBooksgetTitle 是简单的同步函数,我认为将Promise 与executor 函数一起使用是对Promise 的滥用。我们可以将它们重写得更简单 -

    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"))
    }
    

    其中BOOKSTITLES 定义为-

    const BOOKS =
      [
        {
          bookId: 1,
          author: "bob"
        },
        {
          bookId: 2,
          author: "sally"
        }
      ]
    
    const TITLES =
      {
        1: "Greeting the World",
        2: "Hello World!"
      }
    

    展开下面的sn-p,在自己的浏览器中验证结果-

    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)

    【讨论】:

      猜你喜欢
      • 2020-07-04
      • 1970-01-01
      • 2021-11-09
      • 2015-07-09
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多