Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Check for changes once per name
  • Loading branch information
zodern authored and benjamn committed Jul 13, 2021
commit 407e80e7ca352ae7cfc48778ce658b6eaa6ad137
141 changes: 90 additions & 51 deletions lib/runtime/entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ function Entry(id) {
// The normalized namespace object that importers receive when they use
// `import * as namespace from "..."` syntax.
this.namespace = utils.createNamespace();

this._lastValues = Object.create(null);
this._uninitializedSetters = [];
}

var Ep = utils.setPrototypeOf(Entry.prototype, null);
Expand Down Expand Up @@ -98,6 +101,12 @@ Ep.addSetters = function (parent, setters, key) {
entry.setters[name] = Object.create(null);
}
entry.setters[name][key] = setter;

this._uninitializedSetters.push({
name: name,
key: key,
setter: setter
});
}
}

Expand Down Expand Up @@ -214,7 +223,8 @@ Ep.runSetters = function (names) {
// module objects whose setters we might need to run.
var parents;

forEachSetter(this, names, function (setter, name, value) {

function runSetter(setter, name, value) {
if (parents === void 0) {
parents = Object.create(null);
}
Expand All @@ -223,7 +233,23 @@ Ep.runSetters = function (names) {
// The param order for setters is `value` then `name` because the `name`
// param is only used by namespace exports.
setter(value, name);
});
}

forEachSetter(this, names, undefined, runSetter);

if (this._uninitializedSetters.length > 0) {
var initNames = [];
var initKeys = [];
this._uninitializedSetters.forEach(function (config) {
if (config.setter.initialized) {
return;
}
initNames.push(config.name);
initKeys.push(config.key);
});
this._uninitializedSetters.length = 0;
forEachSetter(this, initNames, initKeys, runSetter);
}

if (! parents) {
return;
Expand Down Expand Up @@ -254,64 +280,32 @@ function callSetterIfNecessary(setter, name, value, callback) {
return;
}

var shouldCall = false;
setter.initialized = true;
return callback(setter, name, value);
}

if (setter.last === void 0) {
setter.last = Object.create(null);
// Always call the setter if it has never been called before.
shouldCall = true;
function changed(last, prop, value) {
var valueToCompare = value;
if (valueToCompare !== valueToCompare) {
valueToCompare = NAN;
} else if (valueToCompare === void 0) {
valueToCompare = UNDEFINED;
}

function changed(name, value) {
var valueToCompare = value;
if (valueToCompare !== valueToCompare) {
valueToCompare = NAN;
} else if (valueToCompare === void 0) {
valueToCompare = UNDEFINED;
}

if (setter.last[name] === valueToCompare) {
return false;
}

setter.last[name] = valueToCompare;
return true;
if (last[prop] === valueToCompare) {
return false;
}

if (name === "*") {
var keys = safeKeys(value);
var keyCount = keys.length;
for (var i = 0; i < keyCount; ++i) {
var key = keys[i];
// Evaluating value[key] is risky because the property might be
// defined by a getter function that logs a deprecation warning (or
// worse) when evaluated. For example, Node uses this trick to
// display a deprecation warning whenever crypto.createCredentials
// is accessed. Fortunately, when value[key] is defined by a getter
// function, it's enough to check whether the getter function itself
// has changed, since we are careful elsewhere to preserve getters
// rather than prematurely evaluating them.
if (changed(key, utils.valueOrGetter(value, key))) {
shouldCall = true;
}
}
} else if (changed(name, value)) {
shouldCall = true;
}

if (shouldCall) {
// Only invoke the callback if we have not called this setter
// (with a value of this name) before, or the current value is
// different from the last value we passed to this setter.
return callback(setter, name, value);
}
last[prop] = valueToCompare;
return true;
}

// Invoke the given callback once for every (setter, name, value) that needs to
// be called. Note that forEachSetter does not call any setters itself, only the
// given callback.
function forEachSetter(entry, names, callback) {
function forEachSetter(entry, names, keys, callback) {
var needToCheckNames = true;
var keysProvided = keys !== void 0;

if (names === void 0) {
names = Object.keys(entry.setters);
Expand All @@ -328,13 +322,58 @@ function forEachSetter(entry, names, callback) {
continue;
}

var value = getExportByName(entry, name);
var shouldCall = false;

if (!hasOwn.call(entry._lastValues, name)) {
entry._lastValues[name] = Object.create(null);
}

var last = entry._lastValues[name];

if (!shouldCall && name === "*") {
var keysToCheck = safeKeys(value);
var keyCount = keysToCheck.length;
for (var x = 0; x < keyCount; ++x) {
var key = keysToCheck[x];
// Evaluating value[key] is risky because the property might be
// defined by a getter function that logs a deprecation warning (or
// worse) when evaluated. For example, Node uses this trick to
// display a deprecation warning whenever crypto.createCredentials
// is accessed. Fortunately, when value[key] is defined by a getter
// function, it's enough to check whether the getter function itself
// has changed, since we are careful elsewhere to preserve getters
// rather than prematurely evaluating them.
if (changed(last, key, utils.valueOrGetter(value, key))) {
shouldCall = true;
}
}
} else if (!shouldCall && changed(last, name, value)) {
shouldCall = true;
}

// Only invoke the callback if the current value is
// different from the last value we passed to this setter.
// If we need to run setters for the first time even if the value didn't change,
// their keys should be provided to force them to be called
if (!shouldCall && !keysProvided) {
continue;
}

var setters = entry.setters[name];
var keys = Object.keys(setters);
if (!keysProvided) {
keys = Object.keys(setters);
}

var keyCount = keys.length;

for (var j = 0; j < keyCount; ++j) {
var key = keys[j];
var value = getExportByName(entry, name);

if (keysProvided &&
!hasOwn.call(setters, key)) {
continue;
}

callSetterIfNecessary(setters[key], name, value, callback);

Expand Down