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

Reduce bytes #401

Merged
merged 7 commits into from Feb 16, 2018
Merged

Reduce bytes #401

merged 7 commits into from Feb 16, 2018

Conversation

carhartl
Copy link
Member

@carhartl carhartl commented Feb 2, 2018

The goal is to reduce bytes without compromising on readability.

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

bildschirmfoto 2018-02-02 um 10 19 34

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

Ah, the latest commit doesn't seem to help with the gzipped sized... so I can just as well remove it again from the PR, though I like how key + value assignments stand on the same line now.

bildschirmfoto 2018-02-02 um 10 47 06

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

No, if I interprete it correctly, compared to the latest minified release, 2.2.0, we'll get a decrease of 6 bytes when doing a new release with these changes? @FagnerMartinsBrack

@FagnerMartinsBrack
Copy link
Member

... though I like how key + value assignments stand on the same line now

I have just one point that's probably a matter of style, also probably be subjective and I have no evidence to support it:

I've seen people having trouble to understand a codebase with lots of ternary statements. An explicit if is easier to reason about. I would say that, because it's subjective, we can sacrifice explicit ifs in favor of ternary, but when it doesn't make any difference is it worth keeping the explicit if?

Not strong about it, though. It achieved a good result in reducing 5 bytes :)

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

We're using said operator in other places as well, those weren't replaced with explicit if statements either. Thus, imo, the code is even more consistent now. I heard the argument about ternary vs if before and won't deny it, but readability in this case much depends on how huge the operands get and/or whether you start nesting ternary operators. Consistency is equally important to me.

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

I'm not merging yet, because I wanted to take another look, maybe I find another place to take away some bytes.

@FagnerMartinsBrack
Copy link
Member

... but readability in this case much depends on how huge the operands get and/or whether you start nesting ternary operators

Agreed

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

We could do

if (typeof attributes.expires === 'number') {
    attributes.expires = new Date(new Date().getTime() + attributes.expires * 864e+5);
}

and this would result in reduction of 17 bytes altogether in this branch. I'm not too happy about creating two Date instances, but does it really matter? I would have used Date.now() instead of new Date().getTime() but that is only supported in IE 11...

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

new Date(new Date() * 1 + attributes.expires * 864e+5), ha

@FagnerMartinsBrack
Copy link
Member

I don't think there's any problem with more Date instances. There are limits for cookies so one is not supposed to be calling Cookies.get() many times.

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

I guess that would be ok because that line in particular was already obfuscated by that attributes.expires * 864e+5.... :)

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

bildschirmfoto 2018-02-02 um 12 57 47

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

I have to agree though that new Date(new Date() * 1 + attributes.expires * 864e+5) interferes with:

The goal is to reduce bytes without compromising on readability.

🙈

@FagnerMartinsBrack
Copy link
Member

Honestly, as long as it has tests and doesn't break other use cases, I'm fine with it. This codebase is heavily trading off legibility for less bytes already so I don't think it makes much difference.

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

Interesting, I was experimenting with making the extend() function smaller:

function extend () {
	var i = 0;
	var result = {};
	while (arguments[i]) {
		for (var key in arguments[i]) {
			result[key] = arguments[i][key];
		}
		i++;
	}
	return result;
}

With that I'm getting a test failure

>> remove - deletion
>> Message: should delete the cookie
>> Actual: "c="
>> Expected: ""

and I can't figure out why! That function works fine when experimenting in the (node) console, e.g. it produces the same result as the former one... what am I overlooking?

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

Ah, it was because attributes was undefined in the test case.

@carhartl
Copy link
Member Author

carhartl commented Feb 2, 2018

..and then the changes would turn into a -21 👎

This is fun. :)

@carhartl
Copy link
Member Author

carhartl commented Feb 4, 2018

We could change collecting the result(s) to this, would increase savings to 27:

diff --git a/src/js.cookie.js b/src/js.cookie.js
index 4618358..5a90898 100644
--- a/src/js.cookie.js
+++ b/src/js.cookie.js
@@ -38,7 +38,6 @@
 
 	function init (converter) {
 		function api (key, value, attributes) {
-			var result;
 			if (typeof document === 'undefined') {
 				return;
 			}
@@ -58,7 +57,7 @@
 				attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
 
 				try {
-					result = JSON.stringify(value);
+					var result = JSON.stringify(value);
 					if (/^[\{\[]/.test(result)) {
 						value = result;
 					}
@@ -90,16 +89,13 @@
 
 			// Read
 
-			if (!key) {
-				result = {};
-			}
-
 			// To prevent the for loop in the first place assign an empty array
 			// in case there are no cookies at all. Also prevents odd result when
 			// calling "get()"
 			var cookies = document.cookie ? document.cookie.split('; ') : [];
 			var rdecode = /(%[0-9A-Z]{2})+/g;
 			var i = 0;
+			var jar = {};
 
 			for (; i < cookies.length; i++) {
 				var parts = cookies[i].split('=');
@@ -121,18 +117,15 @@
 						} catch (e) {}
 					}
 
+					jar[name] = cookie;
+
 					if (key === name) {
-						result = cookie;
 						break;
 					}
-
-					if (!key) {
-						result[name] = cookie;
-					}
 				} catch (e) {}
 			}
 
-			return result;
+			return key ? jar[key] : jar;
 		}
 
 		api.set = api;

@FagnerMartinsBrack
Copy link
Member

Sounds great! You're having a lot of fun ain't you? :D

@carhartl carhartl added this to the v2.2.1 milestone Feb 4, 2018
@carhartl
Copy link
Member Author

carhartl commented Feb 9, 2018

With that we'd be at -44:

diff --git a/src/js.cookie.js b/src/js.cookie.js
index 4618358..9d48419 100644
--- a/src/js.cookie.js
+++ b/src/js.cookie.js
@@ -38,7 +38,6 @@
 
 	function init (converter) {
 		function api (key, value, attributes) {
-			var result;
 			if (typeof document === 'undefined') {
 				return;
 			}
@@ -58,7 +57,7 @@
 				attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
 
 				try {
-					result = JSON.stringify(value);
+					var result = JSON.stringify(value);
 					if (/^[\{\[]/.test(result)) {
 						value = result;
 					}
@@ -90,19 +89,15 @@
 
 			// Read
 
-			if (!key) {
-				result = {};
-			}
-
 			// To prevent the for loop in the first place assign an empty array
 			// in case there are no cookies at all. Also prevents odd result when
 			// calling "get()"
 			var cookies = document.cookie ? document.cookie.split('; ') : [];
 			var rdecode = /(%[0-9A-Z]{2})+/g;
-			var i = 0;
+			var jar = {};
 
-			for (; i < cookies.length; i++) {
-				var parts = cookies[i].split('=');
+			while (cookies.length) {
+				var parts = cookies.pop().split('=');
 				var cookie = parts.slice(1).join('=');
 
 				if (!this.json && cookie.charAt(0) === '"') {
@@ -111,8 +106,7 @@
 
 				try {
 					var name = parts[0].replace(rdecode, decodeURIComponent);
-					cookie = converter.read ?
-						converter.read(cookie, name) : converter(cookie, name) ||
+					cookie = (converter.read || converter)(cookie, name) ||
 						cookie.replace(rdecode, decodeURIComponent);
 
 					if (this.json) {
@@ -121,18 +115,11 @@
 						} catch (e) {}
 					}
 
-					if (key === name) {
-						result = cookie;
-						break;
-					}
-
-					if (!key) {
-						result[name] = cookie;
-					}
+					jar[name] = cookie;
 				} catch (e) {}
 			}
 
-			return result;
+			return key ? jar[key] : jar;
 		}
 
 		api.set = api;

This removes the break statement for when having found the desired cookie, and this would eventually decrease performance in theory, although only in cases of the cookie we're searching for being more towards the head of the list...

@carhartl
Copy link
Member Author

carhartl commented Feb 9, 2018

Another thing I noticed... @FagnerMartinsBrack

We have

attributes = extend({
    path: '/'
}, api.defaults, attributes);

but why is path: '/' not part of defaults right away (de facto it is a default)?

@carhartl
Copy link
Member Author

carhartl commented Feb 9, 2018

Ah, the test for API for changing defaults told me...

@carhartl
Copy link
Member Author

carhartl commented Feb 9, 2018

-25

I'm reluctant to remove

if (key === name) {
    break;
}

from the loop, which would give us -35, but would have aforementioned performance implications.

@carhartl carhartl force-pushed the reducing-bytes branch 2 times, most recently from 87c1060 to 7b23c3a Compare February 9, 2018 16:24
@carhartl
Copy link
Member Author

-30 was my goal, we have -33 now.

@carhartl
Copy link
Member Author

carhartl commented Feb 11, 2018

feel free to do a git merge

Not sure I understand you. Are you asking to merge these changes manually instead of going ahead and merging them right here?

@carhartl
Copy link
Member Author

carhartl commented Feb 11, 2018

Regarding Browserstack, it's not possible testing IE 6 + 7 without buying a plan:

bildschirmfoto 2018-02-11 um 10 04 03

My Parallels does in fact no longer work, the (old) version I have is not working in High Sierra. I don't have an idea how to test that. I do not even have any licensed Windows XP version any longer, otherwise I could be using Virtualbox I guess.

You cannot even get these versions from https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/

@FagnerMartinsBrack
Copy link
Member

Not sure I understand you. Are you asking to merge these changes manually instead of going ahead and merging them right here?

No no. Feel free to merge from here. The commits from this PR are atomic so it should be fine to have them on master.

As a sidenote:

What I have been done so far is to close the PR from a commit on master with the message Closes gh-xx where xx is the target PR number (see here for an example). Things are much easier if you fetch all the PRs from upstream, then it's just a matter of doing git cherry-pick <hash> on master and push it.

The reason I've been doing this is to be able to standardize the commit messages on master. Github has changed several times how the merge/rebase message is created.

However, it should be fine to merge from the Github UI with or without Squash. Up to you.

@carhartl
Copy link
Member Author

carhartl commented Feb 11, 2018

Regarding Browserstack, it's not possible testing IE 6 + 7 without buying a plan

I've signed up and contacted them, asking for an open source plan for this repository. It's possible to use it with Travis. In case we will get access, I would prepare everything to switch from Saucelabs. We would be able to automate testing browsers including IE 6 and 7 again.

@carhartl
Copy link
Member Author

Tried converting my Paralles images to VirtualBox but all I got is a bluescreen.

@carhartl
Copy link
Member Author

Running out of ideas, I believe I'm going to wait a little more and see whether I get to test on BrowserStack... in the meantime I'm dreaming of removing support for Internet Explorer 6 + 7.

@FagnerMartinsBrack
Copy link
Member

FagnerMartinsBrack commented Feb 12, 2018

I'm dreaming of removing support for Internet Explorer 6 + 7

We can do it, it will just require a major bump to 3.0.0, that's it.

What if you leave the [].slice change to milestone 3.0.0 and then commit everything else and release the version 2.2.1?

It's better to use the milestones to help to remember what to put in the Releases changelog :D

@carhartl
Copy link
Member Author

What if you leave the [].slice change to milestone 3.0.0 and then commit everything else and release the version 2.2.1?

I still have the ambition to find out about [].slice vs arguments anyway. And, taking a second look, it looks like it's possible to download and run Windows XP without needing a license in VirtualBox: https://www.makeuseof.com/tag/download-windows-xp-for-free-and-legally-straight-from-microsoft-si/

And then, the people from BrowserStack have answered already btw:

We are happy you reached out!

BrowserStack loves open source, and has sponsored thousands of projects. Here is more information about our offering and activation process.

What you get for free: Unlimited manual and automated testing for open source websites and mobile apps. Full platform access to Live, Automate, App Live and App Automate (coming soon). Total of 5 user licenses and parallels.

What we request in return: Give us a shoutout on your GitHub project page or website. Post and hyperlink our attached logo, and a line about how you use BrowserStack. We are counting on you to help us spread the word to the open source community.

Next steps:
Sign up for a BrowserStack free trial account.
Add a status badge to your project, if you're using Automate.
Send us your free trial account email ID and the updated GitHub page.

^ If you think it's worth pursuing further, let me know, @FagnerMartinsBrack!

@carhartl
Copy link
Member Author

carhartl commented Feb 12, 2018

Oh, ok, it seems you can just download Windows 7 from https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/, and in Windows 7 itself there's a possibility to run Windows XP, maybe that's the reason why there were no XP images.

@FagnerMartinsBrack
Copy link
Member

If you think it's worth pursuing further, let me know, @FagnerMartinsBrack!

I think it is if you're up to it :D.

Do they have a fix for this? Can they support IE6+?

@carhartl
Copy link
Member Author

carhartl commented Feb 12, 2018

Do they have a fix for this?

I hope, can‘t tell yet. I also remember we had problems running the full test suite in Saucelabs for PRs from outside the original repo, is that still the case?

Can they support IE6+?

Yes, they do! (But not in the trial, only for paid plans and, as far as I understood open source plans, hence the idea to switch.)

@carhartl
Copy link
Member Author

I also remember we had problems running the full test suite in Saucelabs for PRs from outside the original repo

Unless we choose to keep the access key in plain text, which we don’t, nope!

https://docs.travis-ci.com/user/browserstack/

@carhartl
Copy link
Member Author

carhartl commented Feb 16, 2018

At the moment the test suite doesn't even run in IE6, because of Object.keys():

Object.keys(Cookies.get()).forEach(Cookies.remove);

@carhartl
Copy link
Member Author

But once that's fixed, I conclude this branch works fine in IE 6 with all the changes.

This way value + key appear together, visually.
Collecting all cookies in a jar, and when looking for a specific one
breaking out of the loop.

By this we're also sharing one variable less (`result`) for both the
write and read functionality, which will make it easier to modularize
the library in the future.
Falsey is sufficient.
@carhartl
Copy link
Member Author

But once that's fixed

=> 6e42d24

@carhartl carhartl merged commit 3ec5018 into js-cookie:master Feb 16, 2018
@carhartl carhartl deleted the reducing-bytes branch February 16, 2018 08:07
@carhartl
Copy link
Member Author

Browserstack is amazing. I'm working on moving our testing in CI to it next.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants