Skip to content

stage 4 #25

@MyPrototypeWhat

Description

@MyPrototypeWhat

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(){}
    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions