{"action":"created","issue":{"url":"https://api.github.com/repos/bcoin-org/bcoin/issues/72","repository_url":"https://api.github.com/repos/bcoin-org/bcoin","labels_url":"https://api.github.com/repos/bcoin-org/bcoin/issues/72/labels{/name}","comments_url":"https://api.github.com/repos/bcoin-org/bcoin/issues/72/comments","events_url":"https://api.github.com/repos/bcoin-org/bcoin/issues/72/events","html_url":"https://github.com/bcoin-org/bcoin/pull/72","id":179016989,"number":72,"title":"Switch to await/async-like coroutines and a promise-based API","user":{"login":"chjj","id":470564,"avatar_url":"https://avatars.githubusercontent.com/u/470564?v=3","gravatar_id":"","url":"https://api.github.com/users/chjj","html_url":"https://github.com/chjj","followers_url":"https://api.github.com/users/chjj/followers","following_url":"https://api.github.com/users/chjj/following{/other_user}","gists_url":"https://api.github.com/users/chjj/gists{/gist_id}","starred_url":"https://api.github.com/users/chjj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chjj/subscriptions","organizations_url":"https://api.github.com/users/chjj/orgs","repos_url":"https://api.github.com/users/chjj/repos","events_url":"https://api.github.com/users/chjj/events{/privacy}","received_events_url":"https://api.github.com/users/chjj/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":5,"created_at":"2016-09-24T07:35:59Z","updated_at":"2016-09-28T16:39:34Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/bcoin-org/bcoin/pulls/72","html_url":"https://github.com/bcoin-org/bcoin/pull/72","diff_url":"https://github.com/bcoin-org/bcoin/pull/72.diff","patch_url":"https://github.com/bcoin-org/bcoin/pull/72.patch"},"body":"This pull request is almost an entire rewrite of bcoin.\r\n\r\nAsync/await is likely going to be available natively in node.js and chrome within the next 2 or 3 months. Generator-based coroutines are available right now, and it should only require a simple transpiler script to eventually migrate the codebase to async/await.\r\n\r\nI feel bad leaving callbacks behind, but then again, maybe I just have stockholm syndrome with regard to callbacks.\r\n\r\nBenefits:\r\n\r\n- Cleaner more readable code (especially the tests).\r\n- Promise based API.\r\n\r\nDrawbacks:\r\n\r\n- Slightly worse performance, but not by much.\r\n- Generators are currently not supported on some freedom-stealing OSes and browsers (iOS and Safari<=9). For any production browser-side use, bcoin will require babel compilation (thanks, Apple).\r\n\r\nThe second drawback is what I'm worried about most, but is maybe something I can live with, and support will no doubt get better in the future.\r\n\r\nAny input on this big decision would be appreciated. \r\n\r\ncc @ryanxcharles"},"comment":{"url":"https://api.github.com/repos/bcoin-org/bcoin/issues/comments/250223744","html_url":"https://github.com/bcoin-org/bcoin/pull/72#issuecomment-250223744","issue_url":"https://api.github.com/repos/bcoin-org/bcoin/issues/72","id":250223744,"user":{"login":"chjj","id":470564,"avatar_url":"https://avatars.githubusercontent.com/u/470564?v=3","gravatar_id":"","url":"https://api.github.com/users/chjj","html_url":"https://github.com/chjj","followers_url":"https://api.github.com/users/chjj/followers","following_url":"https://api.github.com/users/chjj/following{/other_user}","gists_url":"https://api.github.com/users/chjj/gists{/gist_id}","starred_url":"https://api.github.com/users/chjj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/chjj/subscriptions","organizations_url":"https://api.github.com/users/chjj/orgs","repos_url":"https://api.github.com/users/chjj/repos","events_url":"https://api.github.com/users/chjj/events{/privacy}","received_events_url":"https://api.github.com/users/chjj/received_events","type":"User","site_admin":false},"created_at":"2016-09-28T16:39:34Z","updated_at":"2016-09-28T16:39:34Z","body":"@daira, usually the flow is something like:\r\n\r\n``` js\r\nvar unlock = yield this.locker.lock();\r\ntry {\r\n  return yield this.sameMethodWithoutLock();\r\n} finally {\r\n  unlock();\r\n}\r\n```\r\n\r\nSo `unlock()` is always called no matter what.\r\n\r\nMany functions may alter in-memory state. Locking is needed to avoid mutating the state as another previous job is happening asynchronously.\r\n\r\nCaching is an example:\r\n\r\n``` js\r\nWalletDB.prototype.getWallet = co(function *(id) {\r\n  var wallet = this.cache[id];\r\n  if (wallet)\r\n    return wallet;\r\n  wallet = yield this.db.get(id);\r\n  this.cache[id] = wallet;\r\n  return wallet;\r\n});\r\n```\r\n\r\nNow what happens when we call this function with the same argument twice. Call 1 starts hitting the database, and Call 2 gets executed before Call 1 has added the wallet to the cache. Now we'll end up with two different Wallet objects in memory, which is a problem because the way we structure things, there should only be one wallet object per id in memory at any given time.\r\n\r\nThe solution:\r\n\r\n``` js\r\nvar lock = yield this.readLock.lock(id); // lock is specific to the id\r\ntry {\r\n  return yield this._getWallet(id);\r\n} finally {\r\n  unlock();\r\n}\r\n```\r\n\r\n^ This ensures that no call running in parallel can ever mutate the in-memory state as a job is running."}}
{"actor":{"display_login":"chjj"}}