【问题标题】:Why do I not have access to a parent-scope variable in one "then" block, but I do have access in a subsequent block?为什么我不能在一个“then”块中访问父范围变量,但我可以在后续块中访问?
【发布时间】:2017-07-19 13:35:25
【问题描述】:

我正在为一个开源 Ember 应用程序做出贡献,并且我正在尝试将多个 Promise 链接在一起。下面代码的目的是将用户设置到 PouchDB 存储的 current_user 文档中,然后将他们的 i18n 首选项设置到 preferences 存储中。代码如下:

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

如您所见,userName 变量作为参数传入setCurrentUser 方法。因此,我希望能够在每个 then 块内的每个代码块内访问此参数。

但事实并非如此。我确实可以在块 0、1、3 中访问它,甚至在块 4 中的 catch 范围内都可以访问它。但由于某种原因,我无法在块 2 中访问它。上面的代码,特别是传递带有首选项文档和用户对象的 RSVP 对象,代表了一种使我的代码工作的 hacky 解决方法。但是,我更喜欢这样做:

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');
    return preferences[userName].i18n || preferences['default'].i18n;
  }).then((i18nPreference) => {                            // block 3
    this.set('i18n.locale', i18nPreference);
  }).catch((err) => {                                      // block 4
    console.log(err);
    config.put({_id: 'current_user', value: userName});
  });
}

事实上,我已经尝试了上述方法,但我在块 2 内得到了 Uncaught ReferenceError: userName is not defined,因此被路由到 catch 块。

我的问题是,块 0/1/3/4 和块 2 之间有什么区别,这将允许第一个块访问 userName 但会阻止块 2 这样做?

【问题讨论】:

  • 我有疑问,您要返回 userName ,我们可以从那里输入 }).then((user) => { 吗?这行得通吗?
  • @kumkanillam 我不明白你的意思。您的意思是删除return userName; 行并将}).then((user) => { 向上移动1 行吗?那么我们会将什么传递给下一个then 块?
  • 忽略我的cmets,这是我对promise的误解。对我来说,你的代码看起来不错。可以尝试评论此行doc.value = userName; config.put(doc);
  • 您需要将代码缩减为可重现的示例。实际上,您绝对可以在所有块中访问该变量:jsfiddle.net/Laayk2g1
  • 是否有可能在没有 userName 的情况下调用 setCurrentUser 并且该块只是您出错的第一个地方?

标签: javascript ember.js ecmascript-6 es6-promise


【解决方案1】:

据我所知,userName 在您的代码中没有大写 N(因此它是一个不同的变量):

}).then((user) => {
   let configDB = this.get('configDB');
   let preferences = configDB.get('preferences');
   return preferences[username] || preferences['default'];

您说此代码仅用于说明目的。最好知道返回错误消息的实际代码是什么,以便更好地了解。

【讨论】:

  • 我所说的illustrative purposes 的意思是您引用的代码本质上是伪代码,但是我已经用我尝试过的特定示例更新了示例代码但失败了。我在第 2 块中遇到的错误返回我在问题中提到的错误(即Uncaught ReferenceError: userName is not defined)。
猜你喜欢
  • 2019-11-17
  • 1970-01-01
  • 1970-01-01
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 2017-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多