重构 - 检查 promise 之前是否已经解决

Refactoring - Checking if promise has been resolved before

此函数获取外部提供的用户文件列表API。一旦检索到数据,它就会被保存,因此下次调用它时 returns 之前保存的相同数据。此代码在控制器级别。

var userFiles = {};

function getUserFiles(user) {
  var dfd = $q.defer();

  // Files already have been loaded
  if (userFiles[user.id]) {
    dfd.resolve(userFiles[user.id]);
  } else {

    // Get files for the first time
    Users.getFiles(user).then(function(files) {
      userFiles[user.id] = files;
      dfd.resolve(userFiles[user.id]);
    });
  }

  return dfd.promise;
}

您将如何重构此代码以使其仅调用一次 dfd.resolve?

var userFiles = {};

function getUserFiles(user) {
  var dfd = $q.defer();

  if (!userFiles[user.id]) {
    // Get files for the first time
    Users.getFiles(user).then(function(files) {
      userFiles[user.id] = files;
    });

    dfd.resolve(userFiles[user.id]);
  }

  return dfd.promise;
}

编辑 #2

我有一个甚至 更好 的片段给你:

function getUserFiles(user) {
  return userFiles[user.id] || (userFiles[user.id] = Users.getFiles(user));
}

这将 userFiles[user.id] 设置为 return 由 Users.getFiles(user) 编辑并 return 的承诺。如果 userFiles[user.id] 已经设置(即它是 truth-y)那么它只是 return 之前解决的承诺。

使用这个超短代码段的缺点是您没有进行任何故障检查 - 并且可能最终缓存失败的请求 - 再一次,您也没有在其他代码中进行任何故障检查。

编辑

根据 docs,您可以直接调用 $q.resolve() 而无需创建中间延迟对象 - 即 $q.defer().resolve()

一个小的重构,下面的代码可以避免你在不需要的时候创建一个延迟。如果文件已经加载,您只需要创建一个新的 deferred。否则,您可以 return 调用 Users.getFiles(),像这样:

function getUserFiles(user) {

  // Files already have been loaded
  if (userFiles[user.id]) {

//        See Edit Note
//        return $q.defer().resolve(userFiles[user.id]);
        return $q.resolve(userFiles[user.id]);
  }

  // Get files for the first time
  return Users.getFiles(user)
    .then(function(files) {
      //Cache them
      return (userFiles[user.id] = files);
    });

}