Skip to content

Conversation

@krystofwoldrich
Copy link
Contributor

@krystofwoldrich krystofwoldrich commented Aug 8, 2021

This is PR base on issue #22.

I've tried to keep the dependency on mem at firt, but I've not found any solution where it would make sense. After I added the maxAge map here to the p-memoize there wasn't basically any reason to keep mem in here. Maybe just for the clear function but in my opinien it is cleaner to have here cacheStore then to have dependency just for that purpose.

The only change is in the maxAge, all other behaviour should be unchanged.
Alltho the code would be cleaner if we would create from every function -> async function but I would rather have a bit more complicated code and keep the behaviour.

Let me know what you think or if you see any other nice, cleaner solutions.


Fixes #22

index.js Outdated
cache,
cacheKey
});
if (!isNaN(maxAge)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should fail loudly with a TypeError if maxAge doesn't pass Number.isSafeInteger.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Thanks, this if condition didn't make sense.

index.js Outdated
}
};

if (result && result instanceof Promise) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instanceof is not a good way to check for promises.

Suggested change
if (result && result instanceof Promise) {
if (result && typeof result.then === 'function') {

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you checking for a promise at all? You can just use Promise.resolve().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because Promise.resolve() returns a promise and I think it is better to keep the function working as it is now. That means when it gets a non-promise returning function it won't change it to a promise returrning function.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The docs are pretty clear about it only accepting promise-returning functions though, even though we didn't actually validate that:

Promise-returning or async function to be memoized.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you're right. I guess it's a matter of taste, I didn't want to change the behaviour if not necessary.

But if you look at it as a "bug", then it would make sense to change now.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I see it as a bug.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've used the Promise.resolve() now.

index.js Outdated
cache.delete(cacheKey(arguments_));
const result = fn.apply(this, arguments_);

let resultError = null;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let resultError = null;
let resultError;

The implementation is no longer depending on mem implementation therefore the typying should not either.
Since clearing test is the only one with sync function its testing two thing at once. Therefore it needed to be fecaupled to test only the clear and new test needed to be added to test keeping sync functions sync.
@krystofwoldrich
Copy link
Contributor Author

@sindresorhus You can take a second look, I've made the changes you mentioned.

@sindresorhus sindresorhus merged commit 49a4db9 into sindresorhus:main Sep 17, 2021
Copy link
Collaborator

@fregante fregante left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit late to the party, but I see a major issue and a couple of improvements

try {
return await Promise.resolve(result);
} catch (error) {
resultError = error;
Copy link
Collaborator

@fregante fregante Sep 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's easier to set or clear the cache here, even if you have to duplicate the cache.set call, so you don't have to create temporary result and resultError variables

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is only a matter of preference.
I see this as a more clear approach to have only one cache set.

resultError = error;
throw error;
} finally {
cache.set(key, {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means the cache is set AFTER the promise is fulfilled, which means these 2 calls will not be memoized:

void memFetch()
void memFetch()

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To achieve both initial call memoization and move the start time to the fulfillment, it'd have to first store the call without expiration and then re-add it with the right expiration once it fulfills.

Copy link
Contributor Author

@krystofwoldrich krystofwoldrich Sep 17, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think if someone wants this behaviour there is mem that does exactly that. Altho not exactly, but close.
I'm not sure if this would not bring unexpected behaviour for p-memoize. Since it should be oriented on promise function and this is more not promise usecase.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's totally valid to start multiple promises at the same time though. I agree with @fregante that this is a regression.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it should be oriented on promise function and this is more not promise usecase.

I don't think @fregante made it clear enough in that example, but those are async functions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, guys, I've created a new PR (#25) which solves this.

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

Successfully merging this pull request may close these issues.

maxAge starts on function call instead of on fulfillment

3 participants