与异步调用角问题发挥作用 [英] Angular issue with asynchronous call to function

查看:168
本文介绍了与异步调用角问题发挥作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用工作角指令的localStorage 加载JSON数据。

这很容易用 localStorage.getItem(ID)做的,但现在我想使它通过API调用工作(这反过来从数据库中拉)

我有角工厂code工作和HTTP请求的工作,但在指令code有它扔了 _handleAsyncLoad()功能我。换句话说,我试图使用内置的诺言连载对象从API层回来了。

EX /我已经写了新的匿名功能, _getItemFromAPI:,但不确定我是否需要使用 _handleAsyncLoad:功能。如果不是,有什么保证以最好的方式我连载对象之前返回它填充数据。

\r
\r

angular.module('ui.dashboard')\r
  .factory('DashboardState',['$日志,$ Q','dashboardcontext','$ rootScope',函数($日志,$ Q,dashboardcontext,$ rootScope){\r
      功能DashboardState(存储,ID,哈希,widgetDefinitions,字符串化){\r
          this.storage =存储;\r
          this.id = ID;\r
          this.hash =散列;\r
          this.widgetDefinitions = widgetDefinitions;\r
          this.stringify =字符串化;\r
      }\r
\r
DashboardState.prototype = {\r
        \r
载:函数(dashboardId){\r
\r
      如果(!this.storage){\r
返回null;\r
      }\r
\r
      VAR系列化;\r
\r
      //获取从存储仪表盘布局\r
      如果(dashboardId = NULL&放大器;!&安培;!dashboardId =未定义){\r
//连载= this.storage.getItem(dashboardId); //年纪大了,更简单的方法\r
\r
系列化= this._getItemFromAPI($ rootScope); //新路子,提取数据,通过API!\r
      }\r
      其他{\r
//恢复原线;看到dashboardOptions主控制器\r
系列化= this.storage.getItem(this.id);\r
      }\r
\r
      如果(连载){\r
//检查承诺\r
如果(angular.isObject(序列)){\r
返回this._handleAsyncLoad(连载)\r
}\r
//否则处理同步负载\r
返回this._handleSyncLoad(连载)\r
      }其他{\r
返回null;\r
      }\r
  },\r
\r
  _getItemFromAPI:函数($ rootscope){\r
      //服务器端API调用持久化仪表盘储存 - 2015年9月3日BM:\r
      VAR SID = $ rootScope.rageSessionVars.sessionID;\r
      VAR的userid = $ rootScope.rageSessionVars.userID;\r
      VAR dashboardId = this.id;\r
\r
      dashboardcontext.getDashboardImage(SID,用户ID,dashboardId)。然后(功能(数据){\r
如果(data.status ==FAIL){\r
window.alert(无法​​检索仪表板。+ data.messages);\r
返回false;\r
}\r
其他{\r
返回的数据;\r
}\r
      });\r
      返回新希望(函数(解析,拒绝){});\r
  },\r
\r
  _handleSyncLoad:功能(连载){\r
\r
      无功序列化,结果= [];\r
\r
      如果(!连载){\r
返回null;\r
      }\r
\r
      如果(this.stringify){\r
尝试{//反序列化字符串\r
\r
反序列化= JSON.parse(连载)\r
\r
}赶上(E){\r
\r
//错误的JSON,记录警告和返回\r
$ log.warn('序列化仪表盘状态是畸形的,不能解析:连载);\r
返回null;\r
\r
}\r
      }\r
      其他{\r
反序列化的序列化=;\r
      }\r
\r
      //缓存部件\r
      VAR savedWidgetDefs = deserialized.widgets;\r
\r
      返回结果;\r
  },\r
\r
  _handleAsyncLoad:功能(承诺){\r
      VAR自我=这一点;\r
      变种推迟= $ q.defer();\r
      promise.then(\r
//成功\r
功能(RES){\r
VAR的结果= self._handleSyncLoad(RES);\r
如果(结果){\r
deferred.resolve(结果);\r
}其他{\r
deferred.reject(结果);\r
}\r
},\r
//失败\r
功能(RES){\r
deferred.reject(RES);\r
}\r
      );\r
\r
      返回deferred.promise;\r
  }\r
 };\r
      \r
 返回DashboardState;\r
 }]);

\r

\r
\r

databoardcontext 工厂code:

\r
\r

函数getDashboardImage(SID,用户ID,ID){\r
    VAR rageVars = $ rootScope.rageSessionVars;\r
    VAR URL =HTTP://+ rageVars.domainName +:+ rageVars.port +/ API /仪表板;\r
    VAR SID = rageVars.sessionID;\r
    VAR apiCall =getDashboardImage;\r
    VAR的CssClass =HTML;\r
    VAR REQ = {\r
方法:POST,\r
网址:网址,\r
标题:{\r
内容类型:应用/ JSON',//应用程序/ x-WWW的形式urlen codeD\r
},\r
数据:{SID:SID,apiCall:apiCall,用户名:用​​户ID,ID:ID}\r
    };\r
    变种推迟= $ q.defer();\r
    deferred.notify(检索仪表板的图片...);\r
\r
    $ HTTP(REQ).success(功能(数据,状态,头,配置){\r
\r
deferred.resolve(数据);\r
\r
    })错误(功能(数据,状态,头,配置){\r
\r
的console.log('错误检索仪表盘);\r
deferred.resolve();\r
    });\r
\r
    返回deferred.promise;\r
}

\r

\r
\r

******** UPDATE 2015年9月8日下午2:55:感谢谁提供答案的绅士,我张贴了一些更新code,显示了现在的工作。 ********

\r
\r

angular.module('ui.dashboard')\r
.factory('DashboardState',['$日志,$ Q','dashboardcontext','$ rootScope',函数($日志,$ Q,dashboardcontext,$ rootScope){\r
\r
VAR认为这=; // ***在这里创建新对象。 BELOW重新指定负载:功能***\r
\r
功能DashboardState(存储,ID,哈希,widgetDefinitions,字符串化){\r
  this.storage =存储;\r
  this.id = ID;\r
  this.hash =散列;\r
  this.widgetDefinitions = widgetDefinitions;\r
  this.stringify =字符串化;\r
}\r
\r
DashboardState.prototype = {\r
  保存:功能(部件){\r
     /// SAVE code不再赘述\r
  },\r
  \r
  载:函数(dashboardId){\r
      \r
      VAR useLocalStorage = FALSE; //从localStorage的或通过API层检索 - 2015年9月4日BM:\r
\r
      VAR系列化;\r
\r
      如果(useLocalStorage){//从localStorage的仪表盘布局\r
如果(!this.storage){\r
返回null;\r
}\r
如果(dashboardId = NULL&放大器;!&安培;!dashboardId =未定义){\r
系列化= this.storage.getItem(dashboardId);\r
\r
//保存下一个负载的电流仪表盘的ID\r
this.storage.setItem(defaultDashboardId,dashboardId);\r
}\r
      }\r
      其他{\r
\r
如果(dashboardId = NULL&放大器;!&安培;!dashboardId =未定义){\r
\r
this.storage.setItem(defaultDashboardId,dashboardId);\r
\r
该=这; // ****非常重要重新分配***\r
\r
// *** RETURN在这里非常重要,还有那么()第***\r
返回this._getItemFromAPI($ rootScope)。然后(功能(数据){\r
      \r
返回that._handleSyncLoad(数据,真实); // ***的。现在可以在示波器上***\r
\r
});\r
}\r
其他{\r
//恢复原线;看到dashboardOptions主控制器\r
系列化= this.storage.getItem(this.id);\r
}\r
      }\r
\r
      如果(连载){\r
//检查承诺\r
如果(angular.isObject(序列)){\r
返回this._handleAsyncLoad(连载)\r
}\r
//否则处理同步负载\r
返回this._handleSyncLoad(连载)\r
      }其他{\r
返回null;\r
      }\r
\r
  },\r
\r
  _getItemFromAPI:函数($ rootscope){\r
      //服务器端API调用持久化仪表盘储存 - 2015年9月3日BM:\r
      VAR SID = $ rootScope.rageSessionVars.sessionID;\r
      VAR的userid = $ rootScope.rageSessionVars.userID;\r
      VAR dashboardId = this.id;\r
\r
      返回dashboardcontext.getDashboardImage(SID,用户ID,dashboardId)。然后(功能(数据){\r
返回数据。数据[0];\r
      });\r
  },\r
\r
  _handleSyncLoad:功能(连载,isParsed){\r
      // {@serialized JSON} - 解析和未解析JSON对象\r
      // {@isParsed布尔} - false,如果从localStorage.getItem加载();如果真从API加载,JSON字符串已经解析。\r
\r
      无功序列化,结果= [];\r
\r
      如果(!连载){\r
返回null;\r
      }\r
\r
      如果(isParsed){// JSON已经deserialzed负载:以上;见_getItemFromAPI(),那么数据对象 - 2015年9月4日BM:\r
\r
反序列化的序列化=;\r
\r
      }\r
      其他{\r
如果(this.stringify){\r
尝试{//反序列化字符串\r
\r
反序列化= JSON.parse(连载)\r
\r
}赶上(E){\r
\r
//错误的JSON,记录警告和返回\r
$ log.warn('序列化仪表盘状态是畸形的,不能解析:连载);\r
返回null;\r
\r
}\r
}\r
其他{\r
反序列化的序列化=;\r
}\r
      }\r
\r
      //核对当前哈希散列\r
      如果(deserialized.hash!== this.hash){\r
\r
$ log.info('从存储序列化的仪表板是陈旧的(旧的Hash:'+ deserialized.hash +',新的哈希:'+ this.hash +')');\r
this.storage.removeItem(this.id);\r
返回null;\r
\r
      }\r
\r
      //缓存部件\r
      VAR savedWidgetDefs = deserialized.widgets;\r
\r
      //从实例存储的数据控件\r
      对于(VAR I = 0; I< savedWidgetDefs.length;我++){\r
\r
//反序列化对象\r
VAR savedWidgetDef = savedWidgetDefs [I]\r
\r
//部件定义使用\r
VAR widgetDefinition = this.widgetDefinitions.getByName(savedWidgetDef.name);\r
\r
//检查是否有部件\r
如果(!widgetDefinition){\r
//没有发现小部件的定义,删除和返回false\r
$ log.warn(工具名称为'+ savedWidgetDef.name +'中给出窗口小部件定义的对象没有被发现');\r
继续;\r
}\r
\r
//检查特定部件storageHash\r
如果(widgetDefinition.hasOwnProperty('storageHash')及与放大器;!widgetDefinition.storageHash == savedWidgetDef.storageHash){\r
//定义窗口小部件被发现,但storageHash是陈旧的,删除存储\r
$ log.info('与名称部件定义对象'+ savedWidgetDef.name +'发现'+\r
但小部件定义的storageHash属性不同于上的+\r
序列化小部件的存储加载。从存储哈希:'+ savedWidgetDef.storageHash +''+\r
从WDO散列:'+ widgetDefinition.storageHash +'');\r
继续;\r
}\r
\r
//实例化推部件导致数组\r
result.push(savedWidgetDef);\r
      }\r
\r
      返回结果;\r
  },\r
\r
  _handleAsyncLoad:功能(承诺){\r
      // code一样的原职...\r
  }\r
\r
};\r
\r
返回DashboardState;\r
}]);

\r

\r
\r


解决方案

只要你有异步操作,你应该异步以及公共API,即使在一些或大多数情况下,它是同步。然后该API向用户是一致的。

而不是检查承诺,同步调用转换为一个承诺。

然后

负荷功能可以简化为以下(我离开的一些细节为简洁起见,但你应该了解的更广泛的概念):

 载:函数(dashboardId){  如果(isSync()){
    //同步    VAR数据= this.storage.getItem(dashboardId);    //在承诺包
    返回$ q.resolve(_handleSyncLoad(数据));  }其他{
    //异步    //返回由_getItemFromAPI(所产生的承诺)。则()
    返回_getItemFromAPI()。然后(功能(数据){
      返回_handleSyncLoad(数据);
    });
  }
}

请注意,我假设 _getItemFromAPI() 返回的承诺(在你的情况并非如此),所以它会像以下内容:

 函数_getItemFromAPI(){  // ...  //这个回归是很重要的!它返回由$ HTTP产生的承诺
  返回$ HTTP({...})。然后(功能(响应){
    返回response.data;
  })
}

这使得负荷一致无论是同步或异步的用法:

  dashboardSvc.load(444)。然后(功能(dashboardData){
  $ scope.dashboard = dashboardData;
});

I'm working with an Angular directive which loads JSON data from localStorage.

This was easily done with localStorage.getItem(id), but now I am trying to make it work via an API call (which in turn pulls from a database).

I have the Angular factory code working, and the http requests working, but in the directive code there's a _handleAsyncLoad() function which is throwing me. In other words, I'm trying to use the built-in promise for the serialized object coming back from the API layer.

ex/ I've written the new anonymous function, _getItemFromAPI:, but unsure if I need to use the _handleAsyncLoad: function. If not, what's the best way to ensure my serialized object is populated with data prior to returning it.

angular.module('ui.dashboard')
  .factory('DashboardState', ['$log', '$q', 'dashboardcontext', '$rootScope', function ($log, $q, dashboardcontext, $rootScope) {
      function DashboardState(storage, id, hash, widgetDefinitions, stringify) {
          this.storage = storage;
          this.id = id;
          this.hash = hash;
          this.widgetDefinitions = widgetDefinitions;
          this.stringify = stringify;
      }

DashboardState.prototype = {
        
load: function (dashboardId) {

      if (!this.storage) {
	  return null;
      }

      var serialized;

      // fetch dashboard layout from storage
      if (dashboardId != null && dashboardId != undefined) {
	  //serialized = this.storage.getItem(dashboardId);	// OLDER, SIMPLER WAY 
	  
	  serialized = this._getItemFromAPI($rootScope);	// NEW WAY, PULL DATA VIA API !	  
      }
      else {
	  // revert to original line; see dashboardOptions to main-controller
	  serialized = this.storage.getItem(this.id);
      }

      if (serialized) {
	  // check for promise
	  if (angular.isObject(serialized)) {  
	      return this._handleAsyncLoad(serialized);
	  }
	  // otherwise handle synchronous load
	  return this._handleSyncLoad(serialized);
      } else {
	  return null;
      }
  },         

  _getItemFromAPI: function ($rootscope) {
      // SERVER-SIDE API CALL TO PERSIST DASHBOARD TO STORAGE - 09/03/2015 BM:
      var sid = $rootScope.rageSessionVars.sessionID;
      var userid = $rootScope.rageSessionVars.userID;
      var dashboardId = this.id;

      dashboardcontext.getDashboardImage(sid, userid, dashboardId).then(function (data) {
	  if (data.status == "FAIL") {
	      window.alert("Failed to retrieve dashboard. " + data.messages);
	      return false;
	  }
	  else {                      
	      return data;
	  }
      });
      return new Promise(function (resolve, reject) { });
  },

  _handleSyncLoad: function (serialized) {

      var deserialized, result = [];

      if (!serialized) {
	  return null;
      }

      if (this.stringify) {
	  try { // to deserialize the string

	      deserialized = JSON.parse(serialized);

	  } catch (e) {

	      // bad JSON, log a warning and return
	      $log.warn('Serialized dashboard state was malformed and could not be parsed: ', serialized);
	      return null;

	  }
      }
      else {
	  deserialized = serialized;
      }     

      // Cache widgets
      var savedWidgetDefs = deserialized.widgets;      

      return result;
  },

  _handleAsyncLoad: function (promise) {
      var self = this;
      var deferred = $q.defer();
      promise.then(
	// success
	function (res) {
	    var result = self._handleSyncLoad(res);
	    if (result) {
		deferred.resolve(result);
	    } else {
		deferred.reject(result);
	    }
	},
	// failure
	function (res) {
	    deferred.reject(res);
	}
      );

      return deferred.promise;
  }
 };
      
 return DashboardState;
 }]);

databoardcontext factory code:

function getDashboardImage(sid, userid, id) {
    var rageVars = $rootScope.rageSessionVars;
    var url = "http://" + rageVars.domainName + ":" + rageVars.port + "/api/dashboards";
    var sid = rageVars.sessionID;
    var apiCall = "getDashboardImage";
    var cssClass = "html";
    var req = {
	method: 'POST',
	url: url,
	headers: {
	    'Content-Type': 'application/json', // application/x-www-form-urlencoded
	},
	data: { sid: sid, apiCall: apiCall, userid: userid, id: id }
    };
    var deferred = $q.defer();
    deferred.notify("Retrieving dashboard image...");

    $http(req).success(function (data, status, headers, config) {

	deferred.resolve(data);

    }).error(function (data, status, headers, config) {

	console.log('Error retrieving dashboard ');
	deferred.resolve();
    });

    return deferred.promise;
}

******** UPDATE Sept 8, 2015 2:55pm: Thanks to the gent who provide the answer, I'm posting some updated code to show what is now working. ********

angular.module('ui.dashboard')
.factory('DashboardState', ['$log', '$q', 'dashboardcontext', '$rootScope', function ($log, $q, dashboardcontext, $rootScope) {

var that = this;       // *** CREATED NEW OBJECT HERE. REASSIGN BELOW IN load: FUNCTION ***

function DashboardState(storage, id, hash, widgetDefinitions, stringify) {
  this.storage = storage;
  this.id = id;
  this.hash = hash;
  this.widgetDefinitions = widgetDefinitions;
  this.stringify = stringify;
}

DashboardState.prototype = {
  save: function (widgets) {
     /// SAVE CODE OMITTED FOR BREVITY
  },
  
  load: function (dashboardId) {
      
      var useLocalStorage = false;     // retrieve from localStorage or via API layer - 09/04/2015 BM:

      var serialized;

      if (useLocalStorage) {           // retrieve dashboard layout from localStorage
	  if (!this.storage) {
	      return null;
	  }
	  if (dashboardId != null && dashboardId != undefined) {
	      serialized = this.storage.getItem(dashboardId);

	      // save the current dashboard id for next load
	      this.storage.setItem("defaultDashboardId", dashboardId);
	  }
      }
      else {	  
	  
	  if (dashboardId != null && dashboardId != undefined) {

	      this.storage.setItem("defaultDashboardId", dashboardId);
	      
	      that = this;	// **** VERY IMPORTANT TO REASSIGN ***
	      
// *** RETURN IS VERY IMPORTANT HERE, AS WELL AS THE then() SECTION ***
	      return this._getItemFromAPI($rootScope).then(function (data) {                           		 
      		  
		  return that._handleSyncLoad(data, true);  // *** that. IS NOW AVAILABLE ON THE SCOPE ***

	       });                      
	  }
	  else {
	      // revert to original line; see dashboardOptions to main-controller
	      serialized = this.storage.getItem(this.id);
	  }                  
      }

      if (serialized) {
	  // check for promise
	 if (angular.isObject(serialized)) {    
	      return this._handleAsyncLoad(serialized);
	  }
	  // otherwise handle synchronous load
	  return this._handleSyncLoad(serialized);
      } else {
	  return null;
      }

  },         

  _getItemFromAPI: function ($rootscope) {
      // SERVER-SIDE API CALL TO PERSIST DASHBOARD TO STORAGE - 09/03/2015 BM:
      var sid = $rootScope.rageSessionVars.sessionID;
      var userid = $rootScope.rageSessionVars.userID;
      var dashboardId = this.id;

      return dashboardcontext.getDashboardImage(sid, userid, dashboardId).then(function (data) {
	  return data.data[0];
      });            
  },

  _handleSyncLoad: function (serialized, isParsed) {
      // @serialized {JSON} - parsed or unparsed Json object 
      // @isParsed {Boolean} - false if loaded from localStorage.getItem(); true if loaded from API, Json string already parsed.

      var deserialized, result = [];

      if (!serialized) {
	  return null;
      }

      if (isParsed) {    // JSON already deserialzed in load: above; see _getItemFromAPI().then data object - 09/04/2015 BM:

	deserialized = serialized;               

      }
      else {
	  if (this.stringify) {
	      try { // to deserialize the string

		  deserialized = JSON.parse(serialized);

	      } catch (e) {

		  // bad JSON, log a warning and return
		  $log.warn('Serialized dashboard state was malformed and could not be parsed: ', serialized);
		  return null;

	      }
	  }
	  else {
	      deserialized = serialized;
	  }
      }

      // check hash against current hash
      if (deserialized.hash !== this.hash) {

	  $log.info('Serialized dashboard from storage was stale (old hash: ' + deserialized.hash + ', new hash: ' + this.hash + ')');
	  this.storage.removeItem(this.id);
	  return null;

      }

      // Cache widgets
      var savedWidgetDefs = deserialized.widgets;

      // instantiate widgets from stored data
      for (var i = 0; i < savedWidgetDefs.length; i++) {

	  // deserialized object
	  var savedWidgetDef = savedWidgetDefs[i];

	  // widget definition to use
	  var widgetDefinition = this.widgetDefinitions.getByName(savedWidgetDef.name);

	  // check for no widget
	  if (!widgetDefinition) {
	      // no widget definition found, remove and return false
	      $log.warn('Widget with name "' + savedWidgetDef.name + '" was not found in given widget definition objects');
	      continue;
	  }

	  // check widget-specific storageHash
	  if (widgetDefinition.hasOwnProperty('storageHash') && widgetDefinition.storageHash !== savedWidgetDef.storageHash) {
	      // widget definition was found, but storageHash was stale, removing storage
	      $log.info('Widget Definition Object with name "' + savedWidgetDef.name + '" was found ' +
		'but the storageHash property on the widget definition is different from that on the ' +
		'serialized widget loaded from storage. hash from storage: "' + savedWidgetDef.storageHash + '"' +
		', hash from WDO: "' + widgetDefinition.storageHash + '"');
	      continue;
	  }

	  // push instantiated widget to result array
	  result.push(savedWidgetDef);
      }

      return result;
  },

  _handleAsyncLoad: function (promise) {
      // code same as original post...
  }

};

return DashboardState;
}]);

解决方案

As soon as you have async operation, you should make the public API async as well, even if in some or most cases, it is sync. Then the API to the user is consistent.

Instead of "checking for promise", convert the sync call to a promise.

Your load function could then be simplified to the following (I'm leaving some details for brevity, but you should understand the broader concept):

load: function(dashboardId) {

  if (isSync()){
    // sync

    var data = this.storage.getItem(dashboardId);

    // wrap in a promise
    return $q.resolve(_handleSyncLoad(data));

  } else {
    // async

    // return the promise generated by _getItemFromAPI().then()
    return _getItemFromAPI().then(function(data){
      return _handleSyncLoad(data);
    });
  }
}

Note, that I assumed that _getItemFromAPI() returns a promise (in your case it doesn't), so it would something like the following:

function _getItemFromAPI(){

  // ...

  // this "return" is important! it returns the promise generated by $http
  return $http({...}).then(function(response){
    return response.data;
  })
}

This makes the usage of load consistent whether it's sync or async:

dashboardSvc.load(444).then(function(dashboardData){
  $scope.dashboard = dashboardData;
});

这篇关于与异步调用角问题发挥作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆