1
+ const slice = Array . prototype . slice ;
2
+ function isObject ( val ) {
3
+ return Object === val . constructor ;
4
+ }
5
+
6
+ function isPromise ( obj ) {
7
+ return typeof obj . then === "function" ;
8
+ }
9
+
10
+ function isGenertor ( obj ) {
11
+ return typeof obj . next === "function" && typeof obj . return === "function" && typeof obj . throw === "function" ;
12
+ }
13
+
14
+ function isGenertorFunction ( fn ) {
15
+ try {
16
+ const constructor = fn . constructor ;
17
+ if ( ! constructor ) {
18
+ return false ;
19
+ }
20
+ if ( constructor . name === "GeneratorFunction" ) {
21
+ return true ;
22
+ }
23
+ return isGenertor ( constructor . prototype ) ;
24
+ } catch ( e ) {
25
+ return false ;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * @param {* } thunk -> 将参数与回调函数分离 fn(p1, p2, cb) -> thunk(p1, p2)(cb)
31
+ */
32
+ function thunkToPromise ( thunk ) {
33
+ const ctx = this ;
34
+ return new Promise ( ( resolve , reject ) => {
35
+ thunk . call ( ctx , ( err , res ) => {
36
+ if ( err ) return reject ( err ) ;
37
+ if ( arguments . length > 2 ) {
38
+ res = slice . call ( arguments , 1 ) ;
39
+ }
40
+ resolve ( res ) ;
41
+ } )
42
+ } )
43
+ }
44
+
45
+ function objectToPromise ( obj ) {
46
+ const results = new obj . constructor ( ) ;
47
+ const keys = Reflect . ownKeys ( obj ) ;
48
+ const promises = [ ] ;
49
+ for ( let i = 0 ; i < keys . length ; i ++ ) {
50
+ const key = keys [ i ] ;
51
+ const promise = toPromise . call ( this , obj [ key ] ) ;
52
+ if ( promise && isPromise ( promise ) ) {
53
+ defer ( promise , key )
54
+ } else {
55
+ results [ key ] = obj [ key ]
56
+ }
57
+ }
58
+ return Promise . all ( promises ) . then ( ( ) => results ) ;
59
+ function defer ( promise , key ) {
60
+ results [ key ] = undefined ;
61
+ promises . push ( promise . then ( res => {
62
+ results [ key ] = res ;
63
+ } ) )
64
+ }
65
+ }
66
+
67
+ function arrayToPromise ( arr ) {
68
+ return Promise . all ( arr . map ( toPromise , this ) )
69
+ }
70
+
71
+ function toPromise ( obj ) {
72
+ if ( ! obj ) return obj ;
73
+ if ( isPromise ( obj ) ) return obj ;
74
+ if ( isGenertor ( obj ) || isGenertorFunction ( obj ) ) return co . call ( this , obj ) ;
75
+ if ( typeof obj === "function" ) return thunkToPromise . call ( this , obj ) ;
76
+ if ( Array . isArray ( obj ) ) return arrayToPromise . call ( this , obj ) ;
77
+ if ( isObject ( obj ) ) return objectToPromise . call ( this , obj ) ;
78
+ return obj ;
79
+ }
80
+
81
+ function co ( gen ) {
82
+ const ctx = this ;
83
+ const args = slice . call ( arguments , 1 ) ;
84
+ let it ;
85
+ return new Promise ( ( resolve , reject ) => {
86
+ if ( typeof gen === "function" ) {
87
+ it = gen . apply ( ctx , args ) ;
88
+ }
89
+ if ( ! it || ! isGenertor ( it ) ) {
90
+ return resolve ( it )
91
+ }
92
+ onFulfilled ( ) ;
93
+ function onFulfilled ( res ) {
94
+ let ret ;
95
+ try {
96
+ ret = it . next ( res )
97
+ } catch ( e ) {
98
+ return reject ( e )
99
+ }
100
+ next ( ret )
101
+ }
102
+ function onRejected ( err ) {
103
+ let ret ;
104
+ try {
105
+ ret = it . throw ( err )
106
+ } catch ( e ) {
107
+ return reject ( e )
108
+ }
109
+ next ( ret )
110
+ }
111
+ function next ( ret ) {
112
+ if ( ret . done ) return resolve ( ret . value ) ;
113
+ const value = toPromise . call ( ctx , ret . value ) ;
114
+ if ( value && isPromise ( value ) ) {
115
+ return value . then ( onFulfilled , onRejected )
116
+ }
117
+ return onRejected ( new TypeError ( 'You may only yield a function, promise, generator, array, or object, ' +
118
+ 'but the following object was passed: "' + String ( ret . value ) + '"' ) ) ;
119
+ }
120
+ } )
121
+ }
122
+ co . wrap = function ( fn ) {
123
+ createPromise . __generatorFunction__ = fn ;
124
+ return createPromise ;
125
+ function createPromise ( ) {
126
+ return co . call ( this , fn . apply ( this , arguments ) ) ;
127
+ }
128
+ } ;
129
+ const fs = require ( "fs" ) ;
130
+ const path = require ( 'path' ) ;
131
+ const readFile = function ( filePath ) {
132
+ return new Promise ( ( resolve , reject ) => {
133
+ fs . readFile ( filePath , "utf-8" , ( err , data ) => {
134
+ if ( ! err ) {
135
+ resolve ( data ) ;
136
+ } else {
137
+ reject ( err )
138
+ }
139
+ } )
140
+ } )
141
+ } ;
142
+
143
+ function * generator ( ) {
144
+ const file1 = yield readFile ( path . join ( __dirname , '1.txt' ) ) ;
145
+ console . log ( file1 ) ;
146
+ const file2 = yield readFile ( path . join ( __dirname , '2.txt' ) ) ;
147
+ console . log ( file2 ) ;
148
+ const file3 = yield readFile ( path . join ( __dirname , '1.txt' ) ) ;
149
+ console . log ( file3 ) ;
150
+ const file4 = yield readFile ( path . join ( __dirname , '2.txt' ) ) ;
151
+ console . log ( file4 ) ;
152
+ const file5 = yield readFile ( path . join ( __dirname , '1.txt' ) ) ;
153
+ console . log ( file5 ) ;
154
+ return 666 ;
155
+ }
156
+ co ( generator ) ;
0 commit comments