{"action":"created","issue":{"url":"https://api.github.com/repos/goatslacker/alt/issues/122","labels_url":"https://api.github.com/repos/goatslacker/alt/issues/122/labels{/name}","comments_url":"https://api.github.com/repos/goatslacker/alt/issues/122/comments","events_url":"https://api.github.com/repos/goatslacker/alt/issues/122/events","html_url":"https://github.com/goatslacker/alt/issues/122","id":65719594,"number":122,"title":"Consider an async (promise) allowance for actions / stores","user":{"login":"mehcode","id":753919,"avatar_url":"https://avatars.githubusercontent.com/u/753919?v=3","gravatar_id":"","url":"https://api.github.com/users/mehcode","html_url":"https://github.com/mehcode","followers_url":"https://api.github.com/users/mehcode/followers","following_url":"https://api.github.com/users/mehcode/following{/other_user}","gists_url":"https://api.github.com/users/mehcode/gists{/gist_id}","starred_url":"https://api.github.com/users/mehcode/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mehcode/subscriptions","organizations_url":"https://api.github.com/users/mehcode/orgs","repos_url":"https://api.github.com/users/mehcode/repos","events_url":"https://api.github.com/users/mehcode/events{/privacy}","received_events_url":"https://api.github.com/users/mehcode/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":16,"created_at":"2015-04-01T16:06:21Z","updated_at":"2015-04-14T09:27:14Z","closed_at":null,"body":"As ECMAScript 6 (and even 7) features become easier to achieve and use in a project, I feel that we should have allowances for using (what is now) first-class asynchronous primitives: Promises.\r\n\r\n*Stores* may return promises in a handling method.\r\n\r\n```js\r\nexport default alt.createStore(class Store {\r\n  // [...]\r\n  onSend() {\r\n    // This becomes much nicer when we can do \"async onSend() [...]\" in ES7\r\n    return new Promise((resolve, reject) => { \r\n      resolve();\r\n    });\r\n  }\r\n});\r\n```\r\n\r\n*Actions* return a promise by-default from the dispatch call.\r\n\r\n```js\r\nexport default alt.createActions(class Actions {\r\n  // The actions generated from the shorthand methods become the following:\r\n  send(params) {\r\n    return this.dispatch(params)\r\n  }\r\n});\r\n```\r\n\r\nInternally, `this.dispatch` uses `Promise.all` to wait for all stores to finish execution and returns a chained promise that disposes of the resolved iterable.\r\n\r\n----\r\n\r\nThe above allows for views that invoke actions to easily wait for a success or failure of a possibly asynchronous event.\r\n\r\nThoughts? I'll jump in and implement if we can agree that this is a good proposal for moving forward."},"comment":{"url":"https://api.github.com/repos/goatslacker/alt/issues/comments/92716004","html_url":"https://github.com/goatslacker/alt/issues/122#issuecomment-92716004","issue_url":"https://api.github.com/repos/goatslacker/alt/issues/122","id":92716004,"user":{"login":"jareware","id":560055,"avatar_url":"https://avatars.githubusercontent.com/u/560055?v=3","gravatar_id":"","url":"https://api.github.com/users/jareware","html_url":"https://github.com/jareware","followers_url":"https://api.github.com/users/jareware/followers","following_url":"https://api.github.com/users/jareware/following{/other_user}","gists_url":"https://api.github.com/users/jareware/gists{/gist_id}","starred_url":"https://api.github.com/users/jareware/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jareware/subscriptions","organizations_url":"https://api.github.com/users/jareware/orgs","repos_url":"https://api.github.com/users/jareware/repos","events_url":"https://api.github.com/users/jareware/events{/privacy}","received_events_url":"https://api.github.com/users/jareware/received_events","type":"User","site_admin":false},"created_at":"2015-04-14T09:27:13Z","updated_at":"2015-04-14T09:27:13Z","body":"> Trying to wait for everything may be better accomplished by running your actions and then waiting for the stores to finish updating.\r\n\r\nHow do you know that from stores updating? Isn't it fairly common for `action` to also update the stores (e.g. with an \"action in progress\" flag)? Isn't it possible that triggering `action` will consequently trigger more than just `actionSuccess`? Consider an action that fetches a resource from the server, but then looking at the response may or may not fetch more resources. It would be hard to know how many \"store updates\" you have to wait for, whereas with Promise-able actions it would be as simple as:\r\n\r\n```js\r\ndoAction() {\r\n  return http.get('/data')\r\n    .then(this.actions.receiveData)\r\n    .then(response => {\r\n      if (response.needsMore) {\r\n        return http.get('/more-data')\r\n          .then(this.actions.receiveData)\r\n      }\r\n    })\r\n}\r\n```\r\n\r\nBecause the Promises are chained (notice we always return) you can be sure that whatever `doAction()` kicked off is *completely* done.\r\n\r\n> I would like an easy way to wait for everything to complete from the result of an action.\r\n\r\nIndeed! The only change this would need is the ability to \"collect\" all Promises returned by action dispatches somehow (see above for my suggestion on this).\r\n\r\nIn this case you wouldn't actually even need to be careful to always return the Promise, as the dispatcher would be aware of new operations being kicked off.\r\n\r\n> It feels obtuse to need to have actionFail and actionSuccess for each asynchronous action.\r\n\r\nSome Flux implementations choose to have automagic for this repetition, but given how simple it is to `generateActions()` in Alt I think this would go too far in hiding what's actually happening. That is, in my humble opinion at least. :)"}}