User:Bluedeck/serve/todo.js
外观
注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google Chrome、Firefox、Microsoft Edge及Safari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。
// Author: Bluedeck <bluedeck@outlook.com>
// Licence: CC-BY-SA
// Do NOT import this script. It is not designed to function on its own. You may encounter serious error
// ... were this included imporperly. Consult author before attempting.
function Todo(fn)
{
this.description = "Async todo list - An easy way around call back hell";
this.todo = [];
this.once = false;
this.finalize = null; // insert finalizer function here.
if(fn)
{
this.chain.apply(this, arguments);
}
}
Todo.go = function()
{
if(this.instance.once && this.initiated)
{
return;
}
this.initiated = true;
var target = this.target;
if(this.instance.todo[target])
{
this.instance.todo[target].action.apply(this, arguments);
}
else if(typeof this.instance.finalize === "function")
{
this.instance.finalize.apply(this, arguments);
}
};
// Report itself to be done.
Todo.im_done = function(result)
{
this.done = true;
this.return = result;
if(this.instance.all_done() && typeof this.instance.finalize === "function")
{
this.instance.finalize();
}
};
// Add a chain.
Todo.prototype.chain = function(fn)
{
if(typeof fn === "function" )
{
var todo = {};
todo.target = this.todo.length + 1;
todo.action = fn.bind(todo);
todo.go = Todo.go;
todo.im_done = Todo.im_done;
todo.instance = this;
todo.initiated = false;
todo.done = false;
this.todo.push(todo);
if(arguments.length > 1)
{
var args = [];
for(var i=1; i<arguments.length; i++)
{
args[i-1] = arguments[i];
}
this.chain(args);
}
}
else if(fn.constructor === Array)
{
for(var i=0; i<fn.length; i++)
{
this.chain(fn[i]);
}
}
else
{
throw new TypeError("You can chain one or more functions, an array of functions or nested arrays of " +
"functions using the chain() function. You see this error because you attempted to chain something else. " +
"If you chained an array, every functions before this error should have been chained successfully. If " +
"you catch this error and attempt to go() for it, you might get partial results.");
}
};
// Execute the first chain.
Todo.prototype.go = function()
{
if(this.todo[0])
{
if(!this.once || !this.todo[0].initiated)
{
this.todo[0].initiated = true;
this.todo[0].action.apply(this, arguments);
}
}
};
// Execute the first chain, nothing gets executed more than once.
Todo.prototype.go_once = function()
{
this.once = true;
this.go();
};
// Execute all chains in parallel
Todo.prototype.parallel = function()
{
for(var i=0; i<this.todo.length; i++)
{
if(!this.once || !this.todo[i].initiated)
{
this.todo[i].initated = true;
this.todo[i].action.apply(this, arguments);
}
}
};
// Do all chains in parallel, but don't repeat any single chain.
Todo.prototype.parallel_once = function()
{
this.once = true;
this.parallel();
};
// Chain a finalizer function that gets executed once everyone's done.
Todo.prototype.chain_finalizer = function(fn)
{
if(typeof fn === "function")
{
this.finalize = fn;
}
};
// All actions done??
Todo.prototype.all_done = function()
{
for(var i=0; i<this.todo.length; i++)
{
if(!this.todo[i].done)
{
return false;
}
}
return true;
};
function Todo_nextup()
{
this.actions = [];
this.nextup.apply(this, arguments);
}
Todo_nextup.prototype.nextup = function()
{
if(arguments.length > 0)
{
var todo = new Todo();
todo.im_finalized = false;
todo.im_initiated = false;
todo.chain(function(){this.im_initiated = true;}.bind(todo));
todo.chain.apply(this, arguments);
todo.chain_finalizer(function(){this.im_finalized = true;}.bind(todo));
this.actions.push(todo);
}
if(this.actions.length === 1)
{
this.actions[0].go();
}
else
{
this.attempt_proceed();
}
};
Todo_nextup.prototype.attempt_proceed = function()
{
for(var i=0; i<this.actions.length - 1; i++)
{
if(this.actions[i] !== null && this.actions[i].im_finalized === true && this.actions[i+1].im_initiated === false)
{
this.actions[i+1].go();
}
}
};