mercredi 19 juillet 2017

Why do I not have access to a parent-scope variable in one "then" block, but I do have access in a subsequent block?

I'm contributing to an open-source Ember app, and I'm attempting to chain several promises together. The intent of the code below is to set a user into the current_user document of the PouchDB store, and then set their i18n preferences into the preferences store. Here's the code:

setCurrentUser(userName) {                                 // block 0
  let config = this.get('configDB');
  let sessionData = this.get('sessionData');
  if (!userName && sessionData.authenticated) {
    userName = sessionData.authenticated.name;
  }
  config.get('current_user').then((doc) => {               // block 1
    doc.value = userName;
    config.put(doc);
    return userName;
  }).then((user) => {                                      // block 2
    let configDB = this.get('configDB');
    let preferences = configDB.get('preferences');
    let promises = { user, preferences };
    return RSVP.hash(promises);
  }).then((promises) => {                                 //  block 3
    let { preferences } = promises;
    let userName = promises.user.name || 'default';
    this.set('i18n.locale', preferences[userName].i18n);
  }).catch((err) => {                                      // block 4
    console.log(err);
    config.put({_id: 'current_user', value: userName});
  });
}

As you can see, the userName variable is passed in as a parameter to the setCurrentUser method. Because of this, I would expect to have access to this parameter inside each of the blocks of code inside each then block.

However that's not the case. I do have access to it in blocks 0, 1, 3, and even in the scope of catch in block 4. But for some reason, I don't have access to it in block 2. The above code, specifically the passing of the RSVP object with both the preferences doc and the user object, represents a hacky workaround to make my code work, since I keep getting Uncaught ReferenceError: userName is not defined inside block 2. However, I'd prefer to do something like this (note: code below is for illustrative purposes only, and may have errors):

setCurrentUser(userName) {
  let config = this.get('configDB');
  let sessionData = this.get('sessionData');
  if (!userName && sessionData.authenticated) {
    userName = sessionData.authenticated.name;
  }
  config.get('current_user').then((doc) => {
    doc.value = userName;
    config.put(doc);
    return userName;
  }).then((user) => {
    let configDB = this.get('configDB');
    let preferences = configDB.get('preferences');
    return preferences[username] || preferences['default'];
  }).then((user_preferences) => {
    this.set('i18n.locale', preferences[userName].i18n);
  }).catch((err) => {
    console.log(err);
    config.put({_id: 'current_user', value: userName});
  });
}

My question is, what is the difference between blocks 0/1/3/4 and block 2, which would allow the first blocks to access userName but would prevent block 2 from doing so?




Aucun commentaire:

Enregistrer un commentaire