forked from eggjs/examples
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: async/await Example (eggjs#12)
- Loading branch information
1 parent
0087214
commit c59eef1
Showing
19 changed files
with
626 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
'ues strict'; | ||
|
||
module.exports = { | ||
write: true, | ||
plugin: 'autod-egg', | ||
prefix: '^', | ||
devprefix: '^', | ||
registry: 'https://r.cnpmjs.org', | ||
exclude: [ | ||
'test/fixtures', | ||
], | ||
dep: [ | ||
'egg', | ||
], | ||
devdep: [ | ||
'autod', | ||
'autod-egg', | ||
'eslint', | ||
'eslint-config-egg', | ||
'egg-bin', | ||
], | ||
keep: [ | ||
], | ||
semver: [ | ||
], | ||
test: 'scripts', | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"parserOptions": { | ||
"ecmaVersion": 2017 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
# egg-example-hackernews-async | ||
|
||
[Hacker News](https://news.ycombinator.com/) showcase using async/await for egg | ||
|
||
## QuickStart | ||
|
||
### Development | ||
```shell | ||
$ npm install | ||
$ npm run dev | ||
$ open http://localhost:7001/ | ||
``` | ||
|
||
### Deploy | ||
|
||
Use `EGG_SERVER_ENV=prod` to enable prod mode | ||
|
||
```shell | ||
$ EGG_SERVER_ENV=prod npm start | ||
``` | ||
|
||
### Npm Scripts | ||
|
||
- Use `npm run autod` to auto detect dependencies upgrade | ||
- Use `npm run lint` to check code style | ||
- Use `npm test` to run unit test | ||
|
||
### Requirement | ||
|
||
Please ensure your node version is `>=7.6.0` for async await support without flag. If your node version is `>=7.0.0 < 7.6.0`, you can run npm scripts with harmony flag | ||
|
||
```shell | ||
# start server | ||
npm run dev -- --harmony-async-await | ||
# run test cases | ||
npm run test-local -- --harmony-async-await | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
'use strict'; | ||
|
||
module.exports = app => { | ||
return class NewsController extends app.Controller { | ||
async list() { | ||
const { ctx, app } = this; | ||
const pageSize = app.config.news.pageSize; | ||
const page = parseInt(ctx.query.page) || 1; | ||
|
||
const idList = await ctx.service.hackerNews.getTopStories(page); | ||
|
||
// get itemInfo parallel | ||
const newsList = await Promise.all(idList.map(id => ctx.service.hackerNews.getItem(id))); | ||
await ctx.render('news/list.tpl', { list: newsList, page, pageSize }); | ||
} | ||
|
||
async detail() { | ||
const { ctx } = this; | ||
const id = ctx.params.id; | ||
const newsInfo = await ctx.service.hackerNews.getItem(id); | ||
// get comment parallel | ||
const commentList = await Promise.all(newsInfo.kids.map(id => ctx.service.hackerNews.getItem(id))); | ||
await ctx.render('news/detail.tpl', { item: newsInfo, comments: commentList }); | ||
} | ||
|
||
async user() { | ||
const { ctx } = this; | ||
const id = ctx.params.id; | ||
const userInfo = await ctx.service.hackerNews.getUser(id); | ||
await ctx.render('news/user.tpl', { user: userInfo }); | ||
} | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
'use strict'; | ||
|
||
const moment = require('moment'); | ||
|
||
exports.relativeTime = time => moment(new Date(time * 1000)).fromNow(); | ||
|
||
exports.domain = url => url && url.split('/')[2]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,203 @@ | ||
body, | ||
html { | ||
font-family: Verdana; | ||
font-size: 13px; | ||
height: 100% | ||
} | ||
ul { | ||
list-style-type: none; | ||
padding: 0; | ||
margin: 0 | ||
} | ||
a { | ||
color: #000; | ||
cursor: pointer; | ||
text-decoration: none | ||
} | ||
#wrapper { | ||
background-color: #f6f6ef; | ||
width: 85%; | ||
min-height: 80px; | ||
margin: 0 auto | ||
} | ||
#header, | ||
#wrapper { | ||
position: relative | ||
} | ||
#header { | ||
background-color: #f60; | ||
height: 24px | ||
} | ||
#header h1 { | ||
font-weight: 700; | ||
font-size: 13px; | ||
display: inline-block; | ||
vertical-align: middle; | ||
margin: 0 | ||
} | ||
#header .source { | ||
color: #fff; | ||
font-size: 11px; | ||
position: absolute; | ||
top: 4px; | ||
right: 4px | ||
} | ||
#header .source a { | ||
color: #fff | ||
} | ||
#header .source a:hover { | ||
text-decoration: underline | ||
} | ||
#yc { | ||
border: 1px solid #fff; | ||
margin: 2px; | ||
display: inline-block | ||
} | ||
#yc, | ||
#yc img { | ||
vertical-align: middle | ||
} | ||
.view { | ||
position: absolute; | ||
background-color: #f6f6ef; | ||
width: 100%; | ||
-webkit-transition: opacity .2s ease; | ||
transition: opacity .2s ease; | ||
box-sizing: border-box; | ||
padding: 8px 20px | ||
} | ||
.view.v-enter, | ||
.view.v-leave { | ||
opacity: 0 | ||
} | ||
@media screen and (max-width: 700px) { | ||
body, | ||
html { | ||
margin: 0 | ||
} | ||
#wrapper { | ||
width: 100% | ||
} | ||
} | ||
.news-view { | ||
padding-left: 5px; | ||
padding-right: 15px | ||
} | ||
.news-view.loading:before { | ||
content: "Loading..."; | ||
position: absolute; | ||
top: 16px; | ||
left: 20px | ||
} | ||
.news-view .nav { | ||
padding: 10px 10px 10px 40px; | ||
margin-top: 10px; | ||
border-top: 2px solid #f60 | ||
} | ||
.news-view .nav a { | ||
margin-right: 10px | ||
} | ||
.news-view .nav a:hover { | ||
text-decoration: underline | ||
} | ||
.item { | ||
padding: 2px 0 2px 40px; | ||
position: relative; | ||
-webkit-transition: background-color .2s ease; | ||
transition: background-color .2s ease | ||
} | ||
.item p { | ||
margin: 2px 0 | ||
} | ||
.item .index, | ||
.item .title:visited { | ||
color: #828282 | ||
} | ||
.item .index { | ||
position: absolute; | ||
width: 30px; | ||
text-align: right; | ||
left: 0; | ||
top: 4px | ||
} | ||
.item .domain, | ||
.item .subtext { | ||
font-size: 11px; | ||
color: #828282 | ||
} | ||
.item .domain a, | ||
.item .subtext a { | ||
color: #828282 | ||
} | ||
.item .subtext a:hover { | ||
text-decoration: underline | ||
} | ||
.item-view .item { | ||
padding-left: 0; | ||
margin-bottom: 30px | ||
} | ||
.item-view .item .index { | ||
display: none | ||
} | ||
.item-view .poll-options { | ||
margin-left: 30px; | ||
margin-bottom: 40px | ||
} | ||
.item-view .poll-options li { | ||
margin: 12px 0 | ||
} | ||
.item-view .poll-options p { | ||
margin: 8px 0 | ||
} | ||
.item-view .poll-options .subtext { | ||
color: #828282; | ||
font-size: 11px | ||
} | ||
.item-view .itemtext { | ||
color: #828282; | ||
margin-top: 0; | ||
margin-bottom: 30px | ||
} | ||
.item-view .itemtext p { | ||
margin: 10px 0 | ||
} | ||
.comhead { | ||
font-size: 11px; | ||
margin-bottom: 8px | ||
} | ||
.comhead, | ||
.comhead a { | ||
color: #828282 | ||
} | ||
.comhead a:hover { | ||
text-decoration: underline | ||
} | ||
.comhead .toggle { | ||
margin-right: 4px | ||
} | ||
.comment-content { | ||
margin: 0 0 16px 24px; | ||
word-wrap: break-word | ||
} | ||
.comment-content code { | ||
white-space: pre-wrap | ||
} | ||
.child-comments { | ||
margin: 8px 0 8px 22px | ||
} | ||
.user-view { | ||
color: #828282 | ||
} | ||
.user-view li { | ||
margin: 5px 0 | ||
} | ||
.user-view .label { | ||
display: inline-block; | ||
min-width: 60px | ||
} | ||
.user-view .about { | ||
margin-top: 1em | ||
} | ||
.user-view .links a { | ||
text-decoration: underline | ||
} |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
'use strict'; | ||
|
||
module.exports = app => { | ||
app.redirect('/', '/news'); | ||
app.get('/news', 'news.list'); | ||
app.get('/news/item/:id', 'news.detail'); | ||
app.get('/news/user/:id', 'news.user'); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
'use strict'; | ||
|
||
module.exports = app => { | ||
/** | ||
* HackerNews Api Service | ||
*/ | ||
class HackerNews extends app.Service { | ||
constructor(ctx) { | ||
super(ctx); | ||
this.config = this.ctx.app.config.news; | ||
this.serverUrl = this.config.serverUrl; | ||
this.pageSize = this.config.pageSize; | ||
} | ||
|
||
/** | ||
* request hacker-news api | ||
* @param {String} api - Api name | ||
* @param {Object} [opts] - urllib options | ||
* @return {Promise} response.data | ||
*/ | ||
async request(api, opts) { | ||
const options = Object.assign({ | ||
dataType: 'json', | ||
}, opts); | ||
|
||
const result = await this.ctx.curl(`${this.serverUrl}/${api}`, options); | ||
return result.data; | ||
} | ||
|
||
/** | ||
* get top story ids | ||
* @param {Number} [page] - page number, 1-base | ||
* @param {Number} [pageSize] - page count | ||
* @return {Promise} id list | ||
*/ | ||
async getTopStories(page, pageSize) { | ||
page = page || 1; | ||
pageSize = pageSize || this.pageSize; | ||
|
||
const result = await this.request('topstories.json', { | ||
data: { | ||
orderBy: '"$key"', | ||
startAt: `"${pageSize * (page - 1)}"`, | ||
endAt: `"${pageSize * page - 1}"`, | ||
}, | ||
}); | ||
return Object.keys(result).map(key => result[key]); | ||
} | ||
|
||
/** | ||
* query item | ||
* @param {Number} id - itemId | ||
* @return {Promise} item info | ||
*/ | ||
async getItem(id) { | ||
return await this.request(`item/${id}.json`); | ||
} | ||
|
||
/** | ||
* get user info | ||
* @param {Number} id - userId | ||
* @return {Promise} user info | ||
*/ | ||
async getUser(id) { | ||
return await this.request(`user/${id}.json`); | ||
} | ||
} | ||
|
||
return HackerNews; | ||
}; |
Oops, something went wrong.