-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathpromise.coffee
106 lines (74 loc) · 2.21 KB
/
promise.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
'use strict'
push = Array::push
isFunction = (arg) -> typeof arg is 'function'
defaultOnResolve = (result) -> result
defaultOnReject = (reason) -> throw reason
module.exports =
class Promise
constructor: (executor) ->
@_callbacks = []
resolve = @_resolve true
reject = @_resolve false
try
executor resolve, reject
catch err
reject err
then: (onResolve, onReject) ->
onResolve = defaultOnResolve unless isFunction onResolve
onReject = defaultOnReject unless isFunction onReject
new @constructor (resolve, reject) =>
enqueue = if @_settled then setImmediate else push.bind @_callbacks
enqueue =>
callback = if @_success then onResolve else onReject
try
result = callback @_result
catch err
return reject err
resolve result
catch: (onReject) ->
@then null, onReject
_resolve: (success) -> (result) =>
return if @_resolved
@_resolved = true
if success
if result is this
reason = new TypeError "can't resolve a promise with itself"
@_settle false, reason
return
try
promise = @constructor._normalizeThenable result
catch err
@_settle false, err
return
if promise # resolved with a thenable
promise.then (result) =>
@_settle true, result
,(reason) =>
@_settle false, reason
return
# resolved with a non-thenable or rejected
@_settle success, result
_settle: (success, result) ->
return if @_settled
@_settled = true
@_success = success
@_result = result
setImmediate callback for callback in @_callbacks
@_callbacks = null
@resolve: (value) ->
try
promise = @_normalizeThenable value
catch err
return @reject err
promise or new this (resolve, reject) -> resolve value
@reject: (reason) ->
new this (resolve, reject) -> reject reason
@_normalizeThenable: (arg) ->
thenMethod = arg?.then
return null unless isFunction thenMethod
if arg instanceof this
arg
else if (typeof arg) in ['boolean', 'number']
null
else
new this (resolve, reject) -> thenMethod.call arg, resolve, reject