1

I have an array of objects, there is a function to search for a book by name, I want to use the search function through promises, after a successful search, the convert function should be executed. when I do this, I get an empty array

let book1 = {
  name: "wind",
  author: 'smith',
  size: 314,
};
let book2 = {
  name: "moon",
  author: 'wild',
  size: 421,
};
let book3 = {
  name: "sun",
  author: 'jacob',
  size: 510,
};
let books1 = [book1, book2, book3];
let books = [];

function searchName(search) {
  return new Promise(function(resolve, reject) {
    books1 = books1.filter(function(elem) {
      elem.name.includes(search)
    })
  })
};

function convert() {
  return books = books1.map(item => item.name);
};
searchName("wind").then(convert);
console.log(books);
palaѕн
  • 64,836
  • 15
  • 100
  • 121

2 Answers2

1
  1. Add return statement in book1.filter to get filtered array
  2. Call resolve callback in Promise body
  3. If you do not catch rejected Promise you can omit reject callback in Promise executor's arguments
  4. console.log(books) at the end of your example will always return an empty array because Promise will be executed after the console.log. Read about Microtasks, here is a good explanation https://javascript.info/microtask-queue

Try this code:

    function searchName(search) {
      return new Promise(function (resolve) {
        books1 = books1.filter(function (elem) {
          return elem.name.includes(search);
        });

        if (books1.length) {
          resolve();
        }
      });
    }

    function convert() {
      books = books1.map(item => item.name);

      console.log(books);

      return books;
    }

    searchName('wind').then(convert);
olsdk
  • 666
  • 3
  • 5
0

You're using Promises incorrectly in a variety of ways -

const books =         // use const for bindings that will not be reassigned
  [ { name: "wind"    // objects can be declared in an array, if you wish
    , author: 'smith' // <-- book1
    , size: 314,
    }
  , { name: "moon"    // <-- book2
    , author: 'wild'
    , size: 421
    }
  , { name: "sun"     // <-- book3
    , author: 'jacob'
    , size: 510
    }
  ]
  
const searchBooks = (query = "") =>
  new Promise((resolve, _) =>    // <-- reject unused
    resolve(books.filter(b =>    // call resolve, don't reassign books
      b.name.includes(query)
    ))
  )

const convert = (books = []) =>  // receives argument
  books.map(b => b.name)         // return a value, don't use reassignment

const input =
  document.querySelector("input")
  
input.addEventListener
  ( "keyup"
  , e =>
      searchBooks(e.target.value) // gets filtered books
        .then(convert)            // passes books to convert, gets result
        .then(console.log, console.error) // then log the result, or error
  )
<input placeholder="search here..."/>

These are all common mistakes beginners make when first using Promises. I think this related Q&A will be very helpful to you.


In this example, we wrap a Promise around filter but it is purely synchronous and actually unnecessary -

const searchBooks = (query = "") =>
  books.filter(b =>    
    b.name.includes(query)
  )

In a real scenario, maybe the data is coming from over the network. Then we'd have use for Promises -

const fetchJson = (url = "") =>
  fetch(url).then(res => res.json())

const searchBooks = (query = "") =>
  fetchJson("./path/to/books.json") // fetch the books data
    .then(books =>                  // then using the books
      books.filter(b =>             // filter the books
        b.name.includes(query)
      )
    )                               // .then returns another promise

Related, async/await make it easy to write asynchronous code that appears more like synchronous code. Using async our function will automatically return a Promise, and it allows us to await any expression inside the function's body -

const fetchJson = (url = "") =>
  fetch(url).then(res => res.json())

const searchBooks = async (query = "") => // <-- async keyword
{ const books =     
    await fetchJson("./path/to/books.json") // <-- await keyword

  return books.filter(b => 
    b.name.includes(query)
  )
}
Thank you
  • 107,507
  • 28
  • 191
  • 224