82f2b76e25
We now use webpack instead of SystemJS, effectively bundling modules into one file (plus commons chunks) for every entry point. This results in a much smaller extension size (almost half). Furthermore we use yarn/npm even for extension run-time dependencies. This relieves us from manually vendoring and building dependencies. It's also easier to understand for new developers familiar with node.
293 lines
9.1 KiB
JavaScript
293 lines
9.1 KiB
JavaScript
'use strict';
|
|
var $ = require('./$')
|
|
, LIBRARY = require('./$.library')
|
|
, global = require('./$.global')
|
|
, ctx = require('./$.ctx')
|
|
, classof = require('./$.classof')
|
|
, $export = require('./$.export')
|
|
, isObject = require('./$.is-object')
|
|
, anObject = require('./$.an-object')
|
|
, aFunction = require('./$.a-function')
|
|
, strictNew = require('./$.strict-new')
|
|
, forOf = require('./$.for-of')
|
|
, setProto = require('./$.set-proto').set
|
|
, same = require('./$.same-value')
|
|
, SPECIES = require('./$.wks')('species')
|
|
, speciesConstructor = require('./$.species-constructor')
|
|
, asap = require('./$.microtask')
|
|
, PROMISE = 'Promise'
|
|
, process = global.process
|
|
, isNode = classof(process) == 'process'
|
|
, P = global[PROMISE]
|
|
, empty = function(){ /* empty */ }
|
|
, Wrapper;
|
|
|
|
var testResolve = function(sub){
|
|
var test = new P(empty), promise;
|
|
if(sub)test.constructor = function(exec){
|
|
exec(empty, empty);
|
|
};
|
|
(promise = P.resolve(test))['catch'](empty);
|
|
return promise === test;
|
|
};
|
|
|
|
var USE_NATIVE = function(){
|
|
var works = false;
|
|
function P2(x){
|
|
var self = new P(x);
|
|
setProto(self, P2.prototype);
|
|
return self;
|
|
}
|
|
try {
|
|
works = P && P.resolve && testResolve();
|
|
setProto(P2, P);
|
|
P2.prototype = $.create(P.prototype, {constructor: {value: P2}});
|
|
// actual Firefox has broken subclass support, test that
|
|
if(!(P2.resolve(5).then(function(){}) instanceof P2)){
|
|
works = false;
|
|
}
|
|
// actual V8 bug, https://code.google.com/p/v8/issues/detail?id=4162
|
|
if(works && require('./$.descriptors')){
|
|
var thenableThenGotten = false;
|
|
P.resolve($.setDesc({}, 'then', {
|
|
get: function(){ thenableThenGotten = true; }
|
|
}));
|
|
works = thenableThenGotten;
|
|
}
|
|
} catch(e){ works = false; }
|
|
return works;
|
|
}();
|
|
|
|
// helpers
|
|
var sameConstructor = function(a, b){
|
|
// library wrapper special case
|
|
if(LIBRARY && a === P && b === Wrapper)return true;
|
|
return same(a, b);
|
|
};
|
|
var getConstructor = function(C){
|
|
var S = anObject(C)[SPECIES];
|
|
return S != undefined ? S : C;
|
|
};
|
|
var isThenable = function(it){
|
|
var then;
|
|
return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
|
|
};
|
|
var PromiseCapability = function(C){
|
|
var resolve, reject;
|
|
this.promise = new C(function($$resolve, $$reject){
|
|
if(resolve !== undefined || reject !== undefined)throw TypeError('Bad Promise constructor');
|
|
resolve = $$resolve;
|
|
reject = $$reject;
|
|
});
|
|
this.resolve = aFunction(resolve),
|
|
this.reject = aFunction(reject)
|
|
};
|
|
var perform = function(exec){
|
|
try {
|
|
exec();
|
|
} catch(e){
|
|
return {error: e};
|
|
}
|
|
};
|
|
var notify = function(record, isReject){
|
|
if(record.n)return;
|
|
record.n = true;
|
|
var chain = record.c;
|
|
asap(function(){
|
|
var value = record.v
|
|
, ok = record.s == 1
|
|
, i = 0;
|
|
var run = function(reaction){
|
|
var handler = ok ? reaction.ok : reaction.fail
|
|
, resolve = reaction.resolve
|
|
, reject = reaction.reject
|
|
, result, then;
|
|
try {
|
|
if(handler){
|
|
if(!ok)record.h = true;
|
|
result = handler === true ? value : handler(value);
|
|
if(result === reaction.promise){
|
|
reject(TypeError('Promise-chain cycle'));
|
|
} else if(then = isThenable(result)){
|
|
then.call(result, resolve, reject);
|
|
} else resolve(result);
|
|
} else reject(value);
|
|
} catch(e){
|
|
reject(e);
|
|
}
|
|
};
|
|
while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
|
|
chain.length = 0;
|
|
record.n = false;
|
|
if(isReject)setTimeout(function(){
|
|
var promise = record.p
|
|
, 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);
|
|
}
|
|
} record.a = undefined;
|
|
}, 1);
|
|
});
|
|
};
|
|
var isUnhandled = function(promise){
|
|
var record = promise._d
|
|
, chain = record.a || record.c
|
|
, i = 0
|
|
, reaction;
|
|
if(record.h)return false;
|
|
while(chain.length > i){
|
|
reaction = chain[i++];
|
|
if(reaction.fail || !isUnhandled(reaction.promise))return false;
|
|
} return true;
|
|
};
|
|
var $reject = function(value){
|
|
var record = this;
|
|
if(record.d)return;
|
|
record.d = true;
|
|
record = record.r || record; // unwrap
|
|
record.v = value;
|
|
record.s = 2;
|
|
record.a = record.c.slice();
|
|
notify(record, true);
|
|
};
|
|
var $resolve = function(value){
|
|
var record = this
|
|
, then;
|
|
if(record.d)return;
|
|
record.d = true;
|
|
record = record.r || record; // unwrap
|
|
try {
|
|
if(record.p === value)throw TypeError("Promise can't be resolved itself");
|
|
if(then = isThenable(value)){
|
|
asap(function(){
|
|
var wrapper = {r: record, d: false}; // wrap
|
|
try {
|
|
then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
|
|
} catch(e){
|
|
$reject.call(wrapper, e);
|
|
}
|
|
});
|
|
} else {
|
|
record.v = value;
|
|
record.s = 1;
|
|
notify(record, false);
|
|
}
|
|
} catch(e){
|
|
$reject.call({r: record, d: false}, e); // wrap
|
|
}
|
|
};
|
|
|
|
// constructor polyfill
|
|
if(!USE_NATIVE){
|
|
// 25.4.3.1 Promise(executor)
|
|
P = function Promise(executor){
|
|
aFunction(executor);
|
|
var record = this._d = {
|
|
p: strictNew(this, P, PROMISE), // <- promise
|
|
c: [], // <- awaiting reactions
|
|
a: undefined, // <- checked in isUnhandled reactions
|
|
s: 0, // <- state
|
|
d: false, // <- done
|
|
v: undefined, // <- value
|
|
h: false, // <- handled rejection
|
|
n: false // <- notify
|
|
};
|
|
try {
|
|
executor(ctx($resolve, record, 1), ctx($reject, record, 1));
|
|
} catch(err){
|
|
$reject.call(record, err);
|
|
}
|
|
};
|
|
require('./$.redefine-all')(P.prototype, {
|
|
// 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
|
|
then: function then(onFulfilled, onRejected){
|
|
var reaction = new PromiseCapability(speciesConstructor(this, P))
|
|
, promise = reaction.promise
|
|
, record = this._d;
|
|
reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
|
|
reaction.fail = typeof onRejected == 'function' && onRejected;
|
|
record.c.push(reaction);
|
|
if(record.a)record.a.push(reaction);
|
|
if(record.s)notify(record, false);
|
|
return promise;
|
|
},
|
|
// 25.4.5.1 Promise.prototype.catch(onRejected)
|
|
'catch': function(onRejected){
|
|
return this.then(undefined, onRejected);
|
|
}
|
|
});
|
|
}
|
|
|
|
$export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: P});
|
|
require('./$.set-to-string-tag')(P, PROMISE);
|
|
require('./$.set-species')(PROMISE);
|
|
Wrapper = require('./$.core')[PROMISE];
|
|
|
|
// statics
|
|
$export($export.S + $export.F * !USE_NATIVE, PROMISE, {
|
|
// 25.4.4.5 Promise.reject(r)
|
|
reject: function reject(r){
|
|
var capability = new PromiseCapability(this)
|
|
, $$reject = capability.reject;
|
|
$$reject(r);
|
|
return capability.promise;
|
|
}
|
|
});
|
|
$export($export.S + $export.F * (!USE_NATIVE || testResolve(true)), PROMISE, {
|
|
// 25.4.4.6 Promise.resolve(x)
|
|
resolve: function resolve(x){
|
|
// instanceof instead of internal slot check because we should fix it without replacement native Promise core
|
|
if(x instanceof P && sameConstructor(x.constructor, this))return x;
|
|
var capability = new PromiseCapability(this)
|
|
, $$resolve = capability.resolve;
|
|
$$resolve(x);
|
|
return capability.promise;
|
|
}
|
|
});
|
|
$export($export.S + $export.F * !(USE_NATIVE && require('./$.iter-detect')(function(iter){
|
|
P.all(iter)['catch'](function(){});
|
|
})), PROMISE, {
|
|
// 25.4.4.1 Promise.all(iterable)
|
|
all: function all(iterable){
|
|
var C = getConstructor(this)
|
|
, capability = new PromiseCapability(C)
|
|
, resolve = capability.resolve
|
|
, reject = capability.reject
|
|
, values = [];
|
|
var abrupt = perform(function(){
|
|
forOf(iterable, false, values.push, values);
|
|
var remaining = values.length
|
|
, results = Array(remaining);
|
|
if(remaining)$.each.call(values, function(promise, index){
|
|
var alreadyCalled = false;
|
|
C.resolve(promise).then(function(value){
|
|
if(alreadyCalled)return;
|
|
alreadyCalled = true;
|
|
results[index] = value;
|
|
--remaining || resolve(results);
|
|
}, reject);
|
|
});
|
|
else resolve(results);
|
|
});
|
|
if(abrupt)reject(abrupt.error);
|
|
return capability.promise;
|
|
},
|
|
// 25.4.4.4 Promise.race(iterable)
|
|
race: function race(iterable){
|
|
var C = getConstructor(this)
|
|
, capability = new PromiseCapability(C)
|
|
, reject = capability.reject;
|
|
var abrupt = perform(function(){
|
|
forOf(iterable, false, function(promise){
|
|
C.resolve(promise).then(capability.resolve, reject);
|
|
});
|
|
});
|
|
if(abrupt)reject(abrupt.error);
|
|
return capability.promise;
|
|
}
|
|
}); |