基本使用
function myFunction(params, callback) {
console.log('1',params)
callback(null, '123')
}
var wrapped = nac.timeout(myFunction, 1000);
wrapped({ bar: 'bar' }, function(err, data) {
console.log(data)
});
实现
function timeout(func, millisec, info) {
var callback, timer;
return wrappedFunc;
function wrappedFunc() {
timer = setTimeout(timeoutCallback, millisec);
var args = createArray(arguments);
var lastIndex = args.length - 1;
callback = args[lastIndex];
args[lastIndex] = injectedCallback;
simpleApply(func, args); // 将 warpped 参数传递给 func,修改回调为 injectedCallback 清除定时器并触发 callback
}
function timeoutCallback() {
var name = func.name || 'anonymous';
var err = new Error('Callback function "' + name + '" timed out.');
err.code = 'ETIMEDOUT';
if (info) {
err.info = info;
}
timer = null;
callback(err); // 触发 callback 传递error
}
function injectedCallback() {
if (timer !== null) {
simpleApply(callback, createArray(arguments)); // 触发 callback
clearTimeout(timer);
}
}
function simpleApply(func, args) {
switch (args.length) {
case 0:
func();
break;
case 1:
func(args[0]);
break;
case 2:
func(args[0], args[1]);
break;
default:
func.apply(null, args);
break;
}
}
}
function waterfallIterator(func, args, next) {
switch (args.length) {
case 0:
case 1:
return func(next);
case 2:
return func(args[1], next);
case 3:
return func(args[1], args[2], next);
case 4:
return func(args[1], args[2], args[3], next);
case 5:
return func(args[1], args[2], args[3], args[4], next);
case 6:
return func(args[1], args[2], args[3], args[4], args[5], next);
default:
args = slice(args, 1);
args.push(next);
return func.apply(null, args);
}
}
function waterfall(tasks, callback) {
callback = callback || noop;
if (!checkWaterfallTasks(tasks, callback)) {
return;
}
var func, args, done, sync;
var completed = 0;
var size = tasks.length;
waterfallIterator(tasks[0], [], createCallback(0));
function iterate() {
waterfallIterator(func, args, createCallback(func));
}
function createCallback(index) {
return function next(err, res) {
if (index === undefined) {
callback = noop;
throwError();
}
index = undefined;
if (err) {
done = callback;
callback = throwError;
done(err);
return;
}
if (++completed === size) {
done = callback;
callback = throwError;
if (arguments.length <= 2) {
done(err, res);
} else {
done.apply(null, createArray(arguments));
}
return;
}
if (sync) {
args = arguments;
func = tasks[completed] || throwError;
nextTick(iterate);
} else {
sync = true;
waterfallIterator(tasks[completed] || throwError, arguments, createCallback(completed));
}
sync = false;
};
}
}