Search code examples
javascriptes6-promise

ES6 Promise "pending" vs "fulfilled"


Good Day. Need some fresh eyes. Not sure why my Promise is returning "pending" in the browser's console:

// contact.js (react)
/* trim */
submitForm = (event) => {
    console.log(JSON.stringify(data))
    
    fetch('/contact', {
      method: 'POST',
      headers: {
        'Accept': 'application/json, text/plain, */*',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    }).then( (res) => {
        res.status === 200 ? this.setState({ submitted: true }) : ''
        console.log('submitted: ' + this.state.submitted)
        console.log('status:')
        console.log(res.json())
    })
}
/* trim */


// server.js (node, express)
/* trim */
server.post('/contact', (req, res) => {
    const { emailAddress = '', emailName = '', emailMessage = '' } = req.body
    console.log(req.body) // outputs correct json obj 
    
    let mgData = {
        from: emailName + ' <' + emailAddress + '>',
        to: mailgun_from_who,
        subject: 'From CV Site',
        text: emailMessage,
    }
    const mailgun = require('mailgun-js')({ apiKey: mailgun_api_key, domain: mailgun_domain }) 
    
    /* These work independently 

    mailgun.validate(emailAddress, true, function (error, body) {
        console.log(body) // correctly outputs on server console the json obj returned from mailgun
    }
    mailgun.messages().send(mgData, function (error, body) {
        console.log(body) // correctly outputs on server console the json obj returned from mailgun
    }
    */
    
    /* Now want to promise the validate so if email address does not validate, then 
        I don't want to send the message, but rather return some message to the contact form
        on the browser 
        
       Each call to mailgun returns the correct json obj on the server console, 
        but in the browser's console, the 'status' is 'Promise { <state>: "pending" }'
        So, not sure why that's happening in the code below: */
    
    const validateMsg = new Promise( (resolve, reject) => {
        mailgun.validate(emailAddress, true, function(error,body) {
            if(body) { resolve(body) }
            else { reject(Error(error)) }
        }
    })
    
    // validateMsg.then(successCallback, failureCallback)
    validateMsg.then(
        function(result) {
            console.log('here comes the validate result');
            console.log(result); // validate body
            res.send(result) // should send validate body back to browser as the promise becomes fulfilled. 
        }, function(err) {
            console.log('here comes the validate result');
            console.log(err); // error message
            res.send(err) // should send error message back to the browser as the promise
        }
    )
    
    
})

/* trim */

When I submit the form, and watch the consoles, the browser immediately outputs the data as it should right before the fetch() is called. The same is true on the server console, the data obj is output. Then both wait as mailgun processes the validate request.

As soon as the validate returns from mailgun, the browser outputs:

submitted: true

status:

> Promise {: "pending"}

And at the same time, the server console outputs the json obj returned from mailgun.

So, I'm not sure why the json obj returned from mailgun isn't being sent back to the browser.


Solution

  • res.json() returns a Promise, so you'd have to do something like:

    submitForm = (event) => {
        console.log(JSON.stringify(data))
    
        fetch('/contact', {
          method: 'POST',
          headers: {
            'Accept': 'application/json, text/plain, */*',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(data)
        }).then( (res) => {
            res.status === 200 ? this.setState({ submitted: true }) : '';
            console.log('submitted: ' + this.state.submitted)
            return res.json();
        }).then((data)=>{
            console.log('status:')
            console.log(data)
        });
    }