Skip to content

Commit

Permalink
[icons] New iteration
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Jul 17, 2018
1 parent 6b4942b commit 73464d3
Show file tree
Hide file tree
Showing 13 changed files with 338 additions and 23 deletions.
13 changes: 12 additions & 1 deletion .babelrc
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@
]
},
"development": {
"sourceMaps": "both"
"plugins": [
[
"module-resolver",
{
"alias": {
"modules": "./modules",
}
}
]
]
},
"docs-development": {
"plugins": [
Expand All @@ -40,6 +49,7 @@
"@material-ui/icons": "./packages/material-ui-icons/src",
"@material-ui/lab": "./packages/material-ui-lab/src",
"docs": "./docs",
"modules": "./modules",
"pages": "./pages"
}
}
Expand All @@ -58,6 +68,7 @@
"@material-ui/icons": "./packages/material-ui-icons/src",
"@material-ui/lab": "./packages/material-ui-lab/src",
"docs": "./docs",
"modules": "./modules",
"pages": "./pages"
}
}
Expand Down
9 changes: 2 additions & 7 deletions docs/src/modules/components/Notifications.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import 'isomorphic-fetch';
import React from 'react';
import Button from '@material-ui/core/Button';
import Snackbar from '@material-ui/core/Snackbar';
import sleep from 'modules/waterfall/sleep';

function getLastSeenNotification() {
const seen = document.cookie.replace(
Expand All @@ -13,18 +14,12 @@ function getLastSeenNotification() {
return seen === '' ? 0 : parseInt(seen, 10);
}

function pause(timeout) {
return new Promise(accept => {
setTimeout(accept, timeout);
});
}

let messages = null;

async function getMessages() {
try {
if (!messages) {
await pause(1e3); // Soften the pressure on the main thread.
await sleep(1e3); // Soften the pressure on the main thread.
const result = await fetch(
'https://raw.githubusercontent.com/mui-org/material-ui/master/docs/notifications.json',
);
Expand Down
47 changes: 47 additions & 0 deletions modules/waterfall/Batcher.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Inspired by http://caolan.github.io/async/docs.html#cargo
// The main difference is that we have a timeout.
class Batcher {
pendingEntries = [];

timeout = null;

context = {};

constructor(worker, options = {}) {
// max waiting time before flushing the pending entries (process them)
this.maxWait = options.maxWait || 1000;
// max number of entries in the queue before flushing them (process them)
this.maxItems = options.maxItems || 100;
this.worker = worker;
}

// public method
push(entries, contextItem) {
this.context = contextItem;
this.pendingEntries = this.pendingEntries.concat(entries);

if (this.pendingEntries.length >= this.maxItems) {
return this.sendItems();
}

clearTimeout(this.timeout);
this.timeout = setTimeout(() => {
this.sendItems();
}, this.maxWait);

return null;
}

sendItems() {
const pendingEntries = this.pendingEntries.splice(0); // Transfer the item to the job.
clearTimeout(this.timeout);
return this.worker(pendingEntries, this.context);
}

clear() {
clearTimeout(this.timeout);
this.pendingEntries = [];
}
}

export default Batcher;
59 changes: 59 additions & 0 deletions modules/waterfall/Queue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import waitUntil from './waitUntil';

class Queue {
pendingEntries = [];

inFlight = 0;

err = null;

constructor(worker, options = {}) {
this.worker = worker;
this.concurrency = options.concurrency || 1;
}

push = entries => {
this.pendingEntries = this.pendingEntries.concat(entries);
this.process();
};

process = () => {
const scheduled = this.pendingEntries.splice(0, this.concurrency - this.inFlight);
this.inFlight += scheduled.length;
scheduled.forEach(async task => {
try {
await this.worker(task);
} catch (err) {
this.err = err;
} finally {
this.inFlight -= 1;
}

if (this.pendingEntries.length > 0) {
this.process();
}
});
};

wait = (options = {}) => {
return waitUntil(
() => {
if (this.err) {
this.pendingEntries = [];
throw this.err;
}

return {
predicate: options.empty
? this.inFlight === 0 && this.pendingEntries.length === 0
: this.concurrency > this.pendingEntries.length,
};
},
{
delay: 50,
},
);
};
}

export default Queue;
3 changes: 3 additions & 0 deletions modules/waterfall/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Waterfall

A set of utility functions for handling async/await as scale.
8 changes: 8 additions & 0 deletions modules/waterfall/forEach.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
async function forEach(array, iteratee) {
for (let i = 0; i < array.length; i += 1) {
// eslint-disable-next-line no-await-in-loop
await iteratee(array[i], i);
}
}

export default forEach;
126 changes: 126 additions & 0 deletions modules/waterfall/metric.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// The API is inspired by console.time
// The implementation is isomorphic.
import warning from 'warning';

const times = new Map();

const implementations = {
mark: {
start: name => {
times.set(name, performance.now());
performance.mark(`metric_${name}_start`);
},
end: name => {
const endMark = `metric_${name}_end`;
performance.mark(endMark);
const startMark = `metric_${name}_start`;
performance.measure(name, startMark, endMark);
const duration = performance.getEntriesByName(name)[0].duration;
return duration;
},
},
now: {
start: name => {
times.set(name, performance.now());
},
end: name => {
const time = times.get(name);
const duration = performance.now() - time;
return duration;
},
},
hrtime: {
start: name => {
// https://nodejs.org/api/process.html#process_process_hrtime_time
times.set(name, process.hrtime());
},
end: name => {
const time = times.get(name);
const durations = process.hrtime(time);
const duration = durations[0] / 1e3 + durations[1] / 1e6;
return duration;
},
},
};

let getImplementationCache;

function getImplementation() {
if (getImplementationCache) {
return getImplementationCache;
}

if (typeof performance !== 'undefined' && performance.mark) {
getImplementationCache = implementations.mark;
} else if (typeof performance !== 'undefined' && performance.now) {
getImplementationCache = implementations.now;
} else if (process.hrtime) {
getImplementationCache = implementations.hrtime;
} else {
throw new Error('No performance API available');
}

return getImplementationCache;
}

class Metric {
/**
* Call to begin a measurement.
*/
static start(name) {
warning(!times.get(name), 'Recording already started');
getImplementation().start(name);
}

/**
* Returns the duration of the timing metric. The unit is milliseconds.
* @type {number}
*/
static end(name) {
if (!times.get(name)) {
throw new Error(`No such name '${name}' for metric`);
}

const duration = getImplementation().end(name);
times.delete(name);
return duration;
}

name = '';

/**
* @param {string} name A name for the metric.
*/
constructor(name) {
if (!name) {
throw new Error('Please provide a metric name');
}

this.name = name;
}

/**
* Call to begin a measurement.
*/
start(name) {
if (name) {
throw new Error('The name argument is not supported');
}

Metric.start(this.name);
}

/**
* Returns the duration of the timing metric. The unit is milliseconds.
* @type {number}
*/
end(name) {
if (name) {
throw new Error('The name argument is not supported');
}

return Metric.end(this.name);
}
}

export default Metric;
34 changes: 34 additions & 0 deletions modules/waterfall/retry.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Inspired by https://github.com/zeit/async-retry
// Without the retry dependency (1 kB gzipped +)
async function retry(tryFunction, options = {}) {
const { retries = 3 } = options;

let tries = 0;
let output = null;
let exitErr = null;

const bail = err => {
exitErr = err;
};

while (tries < retries) {
tries += 1;
try {
// eslint-disable-next-line no-await-in-loop
output = await tryFunction({ tries, bail });
break;
} catch (err) {
if (tries >= retries) {
throw err;
}
}
}

if (exitErr) {
throw exitErr;
}

return output;
}

export default retry;
7 changes: 7 additions & 0 deletions modules/waterfall/sleep.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function sleep(delay = 0) {
return new Promise(resolve => {
setTimeout(resolve, delay);
});
}

export default sleep;
17 changes: 17 additions & 0 deletions modules/waterfall/waitUntil.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import sleep from './sleep';

export default async function waitUntil(test, options = {}) {
const { delay = 5e3, tries = -1 } = options;
const { predicate, result } = await test();

if (predicate) {
return result;
}

if (tries - 1 === 0) {
throw new Error('tries limit reached');
}

await sleep(delay);
return waitUntil(test, { ...options, tries: tries > 0 ? tries - 1 : tries });
}
4 changes: 2 additions & 2 deletions packages/material-ui-icons/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"test": "yarn test:unit",
"test:unit": "cd ../../ && ./node_modules/.bin/cross-env NODE_ENV=test ./node_modules/.bin/mocha packages/material-ui-icons/{,**/}*.test.js",
"test:watch": "yarn test:unit --watch",
"download": "../../node_modules/.bin/babel-node ./scripts/download.js",
"download": "cd ../../ && ./node_modules/.bin/babel-node packages/material-ui-icons/scripts/download.js",
"src:icons": "../../node_modules/.bin/babel-node ./builder.js --output-dir ./src --svg-dir ./material-design-icons --glob '/**/*_24px.svg' --renameFilter ./filters/rename/material-design-icons.js",
"prebuild": "../../node_modules/.bin/rimraf material-design-icons && ../../node_modules/.bin/rimraf build",
"build:es2015": "../../node_modules/.bin/cross-env NODE_ENV=production ../../node_modules/.bin/babel ./src --out-dir ./build",
Expand All @@ -43,7 +43,7 @@
"react-dom": "^16.3.0"
},
"dependencies": {
"recompose": "^0.26.0 || ^0.27.0"
"recompose": "^0.27.0"
},
"devDependencies": {
"fs-extra": "^6.0.1",
Expand Down
Loading

0 comments on commit 73464d3

Please sign in to comment.