Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stage 4 #25

Open
MyPrototypeWhat opened this issue Apr 14, 2022 · 0 comments
Open

stage 4 #25

MyPrototypeWhat opened this issue Apr 14, 2022 · 0 comments

Comments

@MyPrototypeWhat
Copy link
Owner

MyPrototypeWhat commented Apr 14, 2022

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(){}
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant