Skip to content

Instantly share code, notes, and snippets.

@susisu
Created April 30, 2014 16:02
Show Gist options
  • Save susisu/313f206f55621e359628 to your computer and use it in GitHub Desktop.
Save susisu/313f206f55621e359628 to your computer and use it in GitHub Desktop.
ES6 Promise のラッパー的な (Chrome(いつからか), Firefox(>=29, JavaScript1.8) で動作します)
this.mosaic = this.mosaic || {};
(function(mosaic)
{
Object.defineProperty(mosaic,
"core", {value: function()
{
this.Action = mosaic.core.Action;
this.wrap = mosaic.core.wrap;
this.fail = mosaic.core.fail;
this.bind = mosaic.core.bind;
this.then = mosaic.core.then;
this.and = mosaic.core.and;
this.or = mosaic.core.or;
this.seq = mosaic.core.seq;
this.all = mosaic.core.all;
this.one = mosaic.core.one;
this.close = mosaic.core.close;
this.handle = mosaic.core.handle;
this.lazy = mosaic.core.lazy;
this.act = mosaic.core.act;
}}
);
Object.defineProperties(mosaic.core, {
Action: {value: function(func)
{
this.func = func;
}},
wrap: {value: function(value)
{
return new mosaic.core.Action(function(){ return Promise.resolve(value); });
}},
fail: {value: function(error)
{
return new mosaic.core.Action(function(){ return Promise.reject(error); });
}},
bind: {value: function(actionA, funcActionB)
{
return new mosaic.core.Action(function()
{
var self = this;
return new Promise(function(resolve, reject)
{
actionA.func.call(self).then(
function(valueA)
{
funcActionB(valueA).func.call(self).then(
function(valueB)
{
resolve(valueB);
},
function(errorB)
{
reject(errorB);
}
);
},
function(errorA)
{
reject(errorA);
}
);
});
});
}},
then: {value: function(actionA, actionB)
{
return mosaic.core.bind(actionA, function(){ return actionB; });
}},
and: {value: function(actionA, actionB)
{
return new mosaic.core.Action(function()
{
var self = this;
return new Promise(function(resolve, reject)
{
var anotherIsResolved= false;
var anotherValue = undefined;
actionA.func.call(self).then(
function(valueA)
{
if(anotherIsResolved)
{
resolve([valueA, anotherValue]);
}
else
{
anotherIsResolved = true;
anotherValue = valueA;
}
},
function(errorA)
{
reject(errorA);
}
);
actionB.func.call(self).then(
function(valueB)
{
if(anotherIsResolved)
{
resolve([anotherValue, valueB]);
}
else
{
anotherIsResolved = true;
anotherValue = valueB;
}
},
function(errorB)
{
reject(errorB);
}
);
});
});
}},
or: {value: function(actionA, actionB)
{
return new mosaic.core.Action(function()
{
var self = this;
return new Promise(function(resolve, reject)
{
var anotherIsRejected = false;
var anotherError = undefined;
actionA.func.call(this).then(
function(valueA)
{
resolve(valueA);
},
function(errorA)
{
if(anotherIsRejected)
{
reject([errorA, anotherError]);
}
else
{
anotherIsRejected = true;
anotherError = errorA;
}
}
);
actionB.func.call(this).then(
function(valueB)
{
resolve(valueB);
},
function(errorB)
{
if(anotherIsRejected)
{
reject([anotherError, errorB]);
}
else
{
anotherIsRejected = true;
anotherError = errorB;
}
}
);
});
});
}},
seq: {value: function()
{
if(arguments.length == 0)
{
return mosaic.core.wrap(undefined);
}
else
{
var action = arguments[0];
for(var i = 1; i < arguments.length; i++)
{
action = mosaic.core.then(action, arguments[i]);
}
return action;
}
}},
all: {value: function()
{
switch(arguments.length)
{
case 0:
return mosaic.core.wrap(undefined);
case 1:
return arguments[0];
default:
var action = mosaic.core.and(arguments[arguments.length - 2], arguments[arguments.length - 1]);
for(var i = arguments.length - 3; i >= 0; i--)
{
action = mosaic.core.bind(mosaic.core.and(arguments[i], action),
function(pair){ return mosaic.core.wrap([pair[0]].concat(pair[1])); });
}
return action;
}
}},
one: {value: function()
{
switch(arguments.length)
{
case 0:
return mosaic.core.wrap(undefined);
case 1:
return arguments[0];
default:
var action = mosaic.core.or(arguments[arguments.length - 2], arguments[arguments.length - 1]);
for(var i = arguments.length - 3; i >= 0; i--)
{
action = mosaic.core.handle(mosaic.core.or(arguments[i], action),
function(pair){ return mosaic.core.fail([pair[0]].concat(pair[1])); });
}
return action;
}
}},
close: {value: function(action)
{
return new mosaic.core.Action(function()
{
return action.func.call(Object.create(this));
});
}},
handle: {value: function(action, handler)
{
return new mosaic.core.Action(function()
{
var self = this;
return new Promise(function(resolve, reject)
{
action.func.call(self).then(
function(valueA)
{
resolve(valueA);
},
function(errorA)
{
handler(errorA).func.call(self).then(
function(valueH)
{
resolve(valueH);
},
function(errorH)
{
reject(errorH);
}
);
}
);
});
});
}},
lazy: {value: function(funcAction)
{
return mosaic.core.bind(mosaic.core.wrap(undefined), funcAction);
}},
act: {value: function(func)
{
return new mosaic.core.Action(func);
}}
});
Object.defineProperties(mosaic.core.Action.prototype, {
run: {value: function()
{
this.runWith({});
}},
runWith: {value: function(state)
{
this.func.call(state);
}},
bind: {value: function(funcAction)
{
return mosaic.core.bind(this, funcAction);
}},
then: {value: function(action)
{
return mosaic.core.then(this, action);
}},
handle: {value: function(handler)
{
return mosaic.core.handle(this, handler);
}},
close: {value: function()
{
return mosaic.core.close(this);
}}
});
})(this.mosaic);
mosaic.core.call(this);
mosaic.std.call(this);
var sleep = function(time)
{
return act(function()
{
return new Promise(function(resolve, reject)
{
setTimeout(function(){ resolve(undefined); }, time);
});
});
};
var log = function(value)
{
return act(function()
{
console.log(value);
return Promise.resolve(undefined);
});
};
var sleepAndWrap = function(time)
{
return seq(
sleep(time),
wrap(time)
);
};
var main =
seq(
sleepAndWrap(100).bind(write("foo")),
read("foo").bind(log),
seq(
read("foo").bind(log),
sleepAndWrap(200).bind(write("foo")),
read("foo").bind(log)
).close(),
read("foo").bind(log)
);
main.run();
// => 100, 100, 200, 100
this.mosaic = this.mosaic || {};
(function(mosaic)
{
Object.defineProperty(mosaic,
"std", {value: function()
{
this.write = mosaic.std.write;
this.read = mosaic.std.read;
}}
);
Object.defineProperties(mosaic.std, {
write: {value: function(name)
{
return function(value)
{
return mosaic.core.act(function()
{
this[name] = value;
return Promise.resolve(undefined);
})
};
}},
read: {value: function(name)
{
return mosaic.core.act(function()
{
return Promise.resolve(this[name]);
});
}}
});
})(this.mosaic);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment