Skip to content

Commit

Permalink
add basic support rejectionHandled / onrejectionhandled event, #140
Browse files Browse the repository at this point in the history
  • Loading branch information
zloirock committed Dec 3, 2015
1 parent 5a35b7a commit e00042d
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 40 deletions.
58 changes: 38 additions & 20 deletions library/modules/es6.promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ var $ = require('./_')
, forOf = require('./_for-of')
, setProto = require('./_set-proto').set
, speciesConstructor = require('./_species-constructor')
, asap = require('./_microtask')
, task = require('./_task').set
, microtask = require('./_microtask')
, PROMISE = 'Promise'
, TypeError = global.TypeError
, process = global.process
Expand Down Expand Up @@ -88,7 +89,7 @@ var notify = function(promise, isReject){
if(promise._n)return;
promise._n = true;
var chain = promise._c;
asap(function(){
microtask(function(){
var value = promise._v
, ok = promise._s == 1
, i = 0;
Expand All @@ -99,7 +100,10 @@ var notify = function(promise, isReject){
, result, then;
try {
if(handler){
if(!ok)promise._h = true;
if(!ok){
if(promise._h == 2)onHandleUnhandled(promise);
promise._h = 1;
}
result = handler === true ? value : handler(value);
if(result === reaction.promise){
reject(TypeError('Promise-chain cycle'));
Expand All @@ -112,40 +116,54 @@ var notify = function(promise, isReject){
}
};
while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
chain.length = 0;
promise._c = [];
promise._n = false;
if(isReject && !promise._h)setTimeout(function(){
var handler, console;
if(isUnhandled(promise)){
if(isNode){
process.emit('unhandledRejection', value, promise);
} else if(handler = global.onunhandledrejection){
handler({promise: promise, reason: value});
} else if((console = global.console) && console.error){
console.error('Unhandled promise rejection', value);
}
} promise._a = undefined;
}, 1);
if(isReject && !promise._h)onUnhandled(promise);
});
};
var onUnhandled = function(promise){
task.call(global, function(){
if(isUnhandled(promise)){
var value = promise._v
, handler, console;
if(isNode){
process.emit('unhandledRejection', value, promise);
} else if(handler = global.onunhandledrejection){
handler({promise: promise, reason: value});
} else if((console = global.console) && console.error){
console.error('Unhandled promise rejection', value);
} promise._h = 2;
} promise._a = undefined;
});
};
var isUnhandled = function(promise){
var chain = promise._a || promise._c
, i = 0
, reaction;
if(promise._h)return false;
if(promise._h == 1)return false;
while(chain.length > i){
reaction = chain[i++];
if(reaction.fail || !isUnhandled(reaction.promise))return false;
} return true;
};
var onHandleUnhandled = function(promise){
task.call(global, function(){
var handler;
if(isNode){
process.emit('rejectionHandled', promise);
} else if(handler = global.onrejectionhandled){
handler({promise: promise, reason: promise._v});
}
});
};
var $reject = function(value){
var promise = this;
if(promise._d)return;
promise._d = true;
promise = promise._w || promise; // unwrap
promise._v = value;
promise._s = 2;
promise._a = promise._c.slice();
if(!promise._a)promise._a = promise._c.slice();
notify(promise, true);
};
var $resolve = function(value){
Expand All @@ -157,7 +175,7 @@ var $resolve = function(value){
try {
if(promise === value)throw TypeError("Promise can't be resolved itself");
if(then = isThenable(value)){
asap(function(){
microtask(function(){
var wrapper = {_w: promise, _d: false}; // wrap
try {
then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
Expand Down Expand Up @@ -194,7 +212,7 @@ if(!USE_NATIVE){
this._s = 0; // <- state
this._d = false; // <- done
this._v = undefined; // <- value
this._h = false; // <- handled rejection
this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled
this._n = false; // <- notify
};
Internal.prototype = require('./_redefine-all')($Promise.prototype, {
Expand Down
58 changes: 38 additions & 20 deletions modules/es6.promise.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ var $ = require('./_')
, forOf = require('./_for-of')
, setProto = require('./_set-proto').set
, speciesConstructor = require('./_species-constructor')
, asap = require('./_microtask')
, task = require('./_task').set
, microtask = require('./_microtask')
, PROMISE = 'Promise'
, TypeError = global.TypeError
, process = global.process
Expand Down Expand Up @@ -88,7 +89,7 @@ var notify = function(promise, isReject){
if(promise._n)return;
promise._n = true;
var chain = promise._c;
asap(function(){
microtask(function(){
var value = promise._v
, ok = promise._s == 1
, i = 0;
Expand All @@ -99,7 +100,10 @@ var notify = function(promise, isReject){
, result, then;
try {
if(handler){
if(!ok)promise._h = true;
if(!ok){
if(promise._h == 2)onHandleUnhandled(promise);
promise._h = 1;
}
result = handler === true ? value : handler(value);
if(result === reaction.promise){
reject(TypeError('Promise-chain cycle'));
Expand All @@ -112,40 +116,54 @@ var notify = function(promise, isReject){
}
};
while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
chain.length = 0;
promise._c = [];
promise._n = false;
if(isReject && !promise._h)setTimeout(function(){
var handler, console;
if(isUnhandled(promise)){
if(isNode){
process.emit('unhandledRejection', value, promise);
} else if(handler = global.onunhandledrejection){
handler({promise: promise, reason: value});
} else if((console = global.console) && console.error){
console.error('Unhandled promise rejection', value);
}
} promise._a = undefined;
}, 1);
if(isReject && !promise._h)onUnhandled(promise);
});
};
var onUnhandled = function(promise){
task.call(global, function(){
if(isUnhandled(promise)){
var value = promise._v
, handler, console;
if(isNode){
process.emit('unhandledRejection', value, promise);
} else if(handler = global.onunhandledrejection){
handler({promise: promise, reason: value});
} else if((console = global.console) && console.error){
console.error('Unhandled promise rejection', value);
} promise._h = 2;
} promise._a = undefined;
});
};
var isUnhandled = function(promise){
var chain = promise._a || promise._c
, i = 0
, reaction;
if(promise._h)return false;
if(promise._h == 1)return false;
while(chain.length > i){
reaction = chain[i++];
if(reaction.fail || !isUnhandled(reaction.promise))return false;
} return true;
};
var onHandleUnhandled = function(promise){
task.call(global, function(){
var handler;
if(isNode){
process.emit('rejectionHandled', promise);
} else if(handler = global.onrejectionhandled){
handler({promise: promise, reason: promise._v});
}
});
};
var $reject = function(value){
var promise = this;
if(promise._d)return;
promise._d = true;
promise = promise._w || promise; // unwrap
promise._v = value;
promise._s = 2;
promise._a = promise._c.slice();
if(!promise._a)promise._a = promise._c.slice();
notify(promise, true);
};
var $resolve = function(value){
Expand All @@ -157,7 +175,7 @@ var $resolve = function(value){
try {
if(promise === value)throw TypeError("Promise can't be resolved itself");
if(then = isThenable(value)){
asap(function(){
microtask(function(){
var wrapper = {_w: promise, _d: false}; // wrap
try {
then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
Expand Down Expand Up @@ -194,7 +212,7 @@ if(!USE_NATIVE){
this._s = 0; // <- state
this._d = false; // <- done
this._v = undefined; // <- value
this._h = false; // <- handled rejection
this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled
this._n = false; // <- notify
};
Internal.prototype = require('./_redefine-all')($Promise.prototype, {
Expand Down

0 comments on commit e00042d

Please sign in to comment.