promise.all-settled
https://github.com/tc39/proposal-promise-allSettled
core-js/packages/core-js/modules/es.promise.all-settled.js
function allSettled(iterable) {
var C = this;
// 创建一个对象,capability属性为
// {
// promise : promise实例
// resolve : promise实例resolve函数
// reject : promise实例reject函数
// }
var capability = newPromiseCapabilityModule.f(C);
var resolve = capability.resolve;
var reject = capability.reject;
// perform:
// function (exec) {
// try {
// return { error: false, value: exec() };
// } catch (error) {
// return { error: true, value: error };
// }
// };
// catch掉同步执行的错误,在最后通过reject抛出
var result = perform(function () {
var promiseResolve = aCallable(C.resolve);
// 存放结果的数组
var values = [];
// 对应values索引
var counter = 0;
// 剩余几个未完成
var remaining = 1;
// 遍历iterable数组,执行第二个参数
iterate(iterable, function (promise) {
var index = counter++;
// 是否被调用
var alreadyCalled = false;
// 每次循环先++
remaining++;
// 相当于Promise.resolve(promise).then()
call(promiseResolve, C, promise).then(function (value) {
if (alreadyCalled) return;
alreadyCalled = true;
values[index] = { status: 'fulfilled', value: value };
// 如果没有剩余就resolve
--remaining || resolve(values);
}, function (error) {
// then第二个参数,用于捕获reject
if (alreadyCalled) return;
alreadyCalled = true;
values[index] = { status: 'rejected', reason: error };
// 同样的减减操作
--remaining || resolve(values);
});
});
// 由于remaining初始是1,所以再次--
--remaining || resolve(values);
});
if (result.error) reject(result.value);
// 返回promise用于后续链式调用
return capability.promise;
}
- 可以看到两层捕获
- 第一层在于
perform函数捕获同步错误,最后通过reject抛出
- 第二层在于
.then第二个入参
- 与
Promise.all源码很类似,都是通过 counter对应结果数组索引 remaining对应未完成数量,不同在于前者 .then第二个入参为 capability.reject
accessible-object-hasownproperty
https://github.com/tc39/proposal-accessible-object-hasownproperty
core-js/packages/core-js/modules/es.object.has-own.js
var uncurryThis = require('../internals/function-uncurry-this');
var toObject = require('../internals/to-object');
var hasOwnProperty = uncurryThis({}.hasOwnProperty);
// `HasOwnProperty` abstract operation
// https://tc39.es/ecma262/#sec-hasownproperty
// eslint-disable-next-line es-x/no-object-hasown -- safe
module.exports = Object.hasOwn || function hasOwn(it, key) {
return hasOwnProperty(toObject(it), key);
};
- 很简单一看就明白了,拿到 通过
uncurryThis包装 hasOwnProperty
globalThis
https://github.com/tc39/proposal-global
core-js/packages/core-js/internals/global.js
很简单,不用注释了
var check = function (it) {
return it && it.Math == Math && it;
};
// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
module.exports =
// eslint-disable-next-line es-x/no-global-this -- safe
check(typeof globalThis == 'object' && globalThis) ||
check(typeof window == 'object' && window) ||
// eslint-disable-next-line no-restricted-globals -- safe
check(typeof self == 'object' && self) ||
check(typeof global == 'object' && global) ||
// eslint-disable-next-line no-new-func -- fallback
(function () { return this; })() || Function('return this')();
Promise.any
https://github.com/tc39/proposal-promise-any
core-js/packages/core-js/modules/es.promise.any.js
var PROMISE_ANY_ERROR = 'No one promise resolved';
// `Promise.any` method
// https://tc39.es/ecma262/#sec-promise.any
$({ target: 'Promise', stat: true }, {
any: function any(iterable) {
var C = this;
var AggregateError = getBuiltIn('AggregateError');
var capability = newPromiseCapabilityModule.f(C);
var resolve = capability.resolve;
var reject = capability.reject;
var result = perform(function () {
var promiseResolve = aCallable(C.resolve);
var errors = [];
var counter = 0;
var remaining = 1;
var alreadyResolved = false;
iterate(iterable, function (promise) {
var index = counter++;
var alreadyRejected = false;
remaining++;
call(promiseResolve, C, promise).then(function (value) {
if (alreadyRejected || alreadyResolved) return;
alreadyResolved = true;
// 只要有一个成功就resolve
resolve(value);
}, function (error) {
if (alreadyRejected || alreadyResolved) return;
alreadyRejected = true;
errors[index] = error;
// 全错才会reject
--remaining || reject(new AggregateError(errors, PROMISE_ANY_ERROR));
});
});
--remaining || reject(new AggregateError(errors, PROMISE_ANY_ERROR));
});
if (result.error) reject(result.value);
return capability.promise;
}
});
- 与
Promise.allSettled逻辑非常相似,不同的是注释的地方,逻辑不同
AggregateError是一种错误类型,可以多种错误包含在一起,感兴趣可以去了解下mdn
relative-indexing-method
https://github.com/tc39/proposal-relative-indexing-method
core-js/packages/core-js/proposals/relative-indexing-method.js
给所有可索引类(Array, String, TypedArray)加上at函数
以 Array为例,其余的感兴趣可以自行了解下
// `Array.prototype.at` method
// https://github.com/tc39/proposal-relative-indexing-method
$({ target: 'Array', proto: true }, {
at: function at(index) {
var O = toObject(this);
var len = lengthOfArrayLike(O);
var relativeIndex = toIntegerOrInfinity(index);
var k = relativeIndex >= 0 ? relativeIndex : len + relativeIndex;
return (k < 0 || k >= len) ? undefined : O[k];
}
});
// 设置Symbol.unscopables
// addToUnscopables:
// function (key) {
// ArrayPrototype[UNSCOPABLES][key] = true;
// };
// 在with环境中at属性不会暴露,感兴趣可以去查下mdn
addToUnscopables('at');
toIntegerOrInfinity:
// `ToIntegerOrInfinity` abstract operation
// https://tc39.es/ecma262/#sec-tointegerorinfinity
module.exports = function (argument) {
var number = +argument;
// eslint-disable-next-line no-self-compare -- safe
// NaN情况 取靠近0的整数
return number !== number || number === 0 ? 0 : (number > 0 ? floor : ceil)(number);
};
String.prototype.matchAll
https://github.com/tc39/proposal-string-matchall
core-js/packages/core-js/modules/es.string.match-all.js
var MATCH_ALL = wellKnownSymbol('matchAll');
var REGEXP_STRING = 'RegExp String';
var REGEXP_STRING_ITERATOR = REGEXP_STRING + ' Iterator';
var setInternalState = InternalStateModule.set;
var getInternalState = InternalStateModule.getterFor(REGEXP_STRING_ITERATOR);
var RegExpPrototype = RegExp.prototype;
var TypeError = global.TypeError;
var getFlags = uncurryThis(regExpFlags);
var stringIndexOf = uncurryThis(''.indexOf);
var un$MatchAll = uncurryThis(''.matchAll);
// 判断是否可以支持没有全局标志的正则
var WORKS_WITH_NON_GLOBAL_REGEX = !!un$MatchAll && !fails(function () {
un$MatchAll('a', /./);
});
// 设置正则表达式迭代器
// 篇幅太长不过多解释,大概流程就是:
// RegExpStringIterator函数为构造函数,设置构造函数的prototype.__proto__[Symbol.iterator]
// 感兴趣可自行查看
var $RegExpStringIterator = createIteratorConstructor(function RegExpStringIterator(regexp, string, $global, fullUnicode) {
setInternalState(this, {
type: REGEXP_STRING_ITERATOR,
regexp: regexp,
string: string,
global: $global,
unicode: fullUnicode,
done: false
});
}, REGEXP_STRING, function next() {
var state = getInternalState(this);
if (state.done) return { value: undefined, done: true };
var R = state.regexp;
var S = state.string;
var match = regExpExec(R, S);
if (match === null) return { value: undefined, done: state.done = true };
if (state.global) {
if (toString(match[0]) === '') R.lastIndex = advanceStringIndex(S, toLength(R.lastIndex), state.unicode);
return { value: match, done: false };
}
state.done = true;
return { value: match, done: false };
});
var $matchAll = function (string) {
// R为正则
var R = anObject(this);
// S为被匹配的字符串
var S = toString(string);
var C, flagsValue, flags, matcher, $global, fullUnicode;
// 拿到构造函数,会通过[Symbol.species]来获取,感兴趣可以看下
C = speciesConstructor(R, RegExp);
// 正则标志位
flagsValue = R.flags;
// isPrototypeOf(RegExpPrototype, R):断正则的原型是否是RegExp.prototype
if (flagsValue === undefined && isPrototypeOf(RegExpPrototype, R) && !('flags' in RegExpPrototype)) {
flagsValue = getFlags(R);
}
flags = flagsValue === undefined ? '' : toString(flagsValue);
// R.source值为正则去掉标志符号和两遍的斜杠
matcher = new C(C === RegExp ? R.source : R, flags);
// 是否含有g标志
$global = !!~stringIndexOf(flags, 'g');
// 是否含有u标志
fullUnicode = !!~stringIndexOf(flags, 'u');
// lastIndex用来指定下一次匹配的起始索引
matcher.lastIndex = toLength(R.lastIndex);
return new $RegExpStringIterator(matcher, S, $global, fullUnicode);
};
// `String.prototype.matchAll` method
// https://tc39.es/ecma262/#sec-string.prototype.matchall
$({ target: 'String', proto: true, forced: WORKS_WITH_NON_GLOBAL_REGEX }, {
// 入口,从这块开始看
matchAll: function matchAll(regexp) {
// 检查this是否是undefined
var O = requireObjectCoercible(this);
var flags, S, matcher, rx;
if (regexp != null) {
// 如果有参数
if (isRegExp(regexp)) {
// 参数是一个正则
// 判断'flags'属性是否存在于RegExp.prototype中
// flags属性返回一个字符串,由当前正则表达式对象的标志组成。
flags = toString(requireObjectCoercible('flags' in RegExpPrototype
? regexp.flags
// 同样是获取标志,只不过是通过判断global,ignoreCase等属性,有兴趣可自行了解
: getFlags(regexp)
));
// 如果正则中未含有g标记,报错
if (!~stringIndexOf(flags, 'g')) throw TypeError('`.matchAll` does not allow non-global regexes');
}
if (WORKS_WITH_NON_GLOBAL_REGEX) return un$MatchAll(O, regexp);
// 相当于regexp[Symbol.matchAll]
matcher = getMethod(regexp, MATCH_ALL);
// 如果matcher为undefined && PURE模式 && regexp为正则
if (matcher === undefined && IS_PURE && classof(regexp) == 'RegExp') matcher = $matchAll;
if (matcher) return call(matcher, regexp, O);
// 同样判断是否支持 没有全局标志的正则的matchAll函数
} else if (WORKS_WITH_NON_GLOBAL_REGEX) return un$MatchAll(O, regexp);
// 走到此处有几种情况,例如
// regexp===null && WORKS_WITH_NON_GLOBAL_REGEX===false
// regexp不为正则
// 等
S = toString(O);
rx = new RegExp(regexp, 'g');
return IS_PURE ? call($matchAll, rx, S) : rx[MATCH_ALL](S);
}
});
-
在设置迭代器的时候是这么设置的
// 简写
// 通常写法:
{
[Symbole.iterator]=function(){
return {
next(){.....}
}
},
}
// corejs中是这么写的
{
[Symbole.iterator]=function(){
return this
},
next:function next(){}
}
promise.all-settled
perform函数捕获同步错误,最后通过reject抛出.then第二个入参Promise.all源码很类似,都是通过counter对应结果数组索引remaining对应未完成数量,不同在于前者.then第二个入参为capability.rejectaccessible-object-hasownproperty
uncurryThis包装hasOwnPropertyglobalThis
Promise.any
Promise.allSettled逻辑非常相似,不同的是注释的地方,逻辑不同AggregateError是一种错误类型,可以多种错误包含在一起,感兴趣可以去了解下mdnrelative-indexing-method
以
Array为例,其余的感兴趣可以自行了解下toIntegerOrInfinity:String.prototype.matchAll
在设置迭代器的时候是这么设置的