Search code examples
javascriptasynchronousasync-awaites6-promise

Promise, Async Await


setDeviceTimeout = id => timeout => {
    const {onSetDevices, devices} = this.props;

    var newDeviceList = devices.map(device => {
        if (device.id === id) {
            var newDevice = {
                //...device,
                timeout: timeout
            };
            deviceTable.oncePostDevice(newDevice).then( data => {
                return newDevice = data
            });
        }
        return device;
    });

    onSetDevices(newDeviceList);
}

So the issue I am having here is that the onSetDevices(newDeviceList) get's called before the devices.map() is finished. This is because the devices.map() has the call to a server oncePostDevice(newDevice), then returns the data and stores it in the newDevice variable and puts that into the newDeviceList array.

Because this happens onSetDevices doesn't include the the newDevice in the newDeviceList array of objects and when I set my redux state using onSetDevices, nothing has changed.

I am wondering how I turn this into an async, await or use a promise alone to finish the task of making onSetDevices wait for the devices.map() to finish.

Also here is the code for oncePostDevice:

export const oncePostDevice = (device) => new Promise(function(resolve, reject) {

    fetch('https://url/devices/'+device.id, {
        method: 'PUT',
        headers: {
            "Accept": "application/json",
            "Content-Type": "application/json"
        },
        body: JSON.stringify(device)
    })
    .then(response => response.json())
    .then(
        data => {return resolve(data)},
        error => {return reject(error)}
    )
    .catch(err => console.error(this.props.url, err.toString()));
});

As you can see I already have a promise in here working and returning the data afterwards.

I just need to know how to make my setDeviceTimeout inner mapping function finish before I hit onSetDevices.


Solution

  • Here's how you could do it (explanations inline in code):

    // make the function async
    setDeviceTimeout = id => async timeout => {
      const {onSetDevices, devices} = this.props;
    
      // make a list of promises, not of devices
      // note: mapping a value via an async function will create promises
      const newDeviceListPromises = devices.map(async device => {
        if (device.id === id) {
          const newDevice = {
            ...device,
            timeout: timeout
          };
          return await deviceTable.oncePostDevice(newDevice);
        }
        return device;
      });
    
      // wait for all promises to finish and what they return will be the devices
      const newDeviceList = await Promise.all(newDeviceListPromises);
    
      onSetDevices(newDeviceList);
    };