npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

magic-task

v0.0.7

Published

JavaScript async programming helper

Downloads

12

Readme

magic-task

Build Status Coverage Status

magic-task可以让JavaScript异步编程更加简单、优雅、安全,它将异步过程抽象成一个个任务,并且使用Promise确保安全可靠,可以做统一的错误处理,还提供了常用的流程控制,使得代码更易于组织。

执行环境

  • node.js - v0.12.x
  • node.js - v0.11.x 开启Promise功能
  • io.js

开始

以下是执行一个典型的异步任务的例子,这个任务包含了调用异步函数获取数据和数据处理过程。

var magicTask = require('magic-task');
var fs = require('fs');
var dealText = function(task) {
    fs.readfile('path', task.async);
    task.done(function(content) {
        console.log(content);
        return doSomething(content);
    });
};
magicTask.run(dealText).then(function(data) {
    console.log(data); // data 等于 doSomething(content)
}).then(null, function(err) {
    console.log(err);
});

当然,仅仅是执行这样简单的文件操作处理并不需要magic-task,直接调用异步函数将处理过程写在回调函数里即可,或是直接使用Promise。在流程稍微复杂的情况下,magic-task才慢慢显示出威力。例如需要多次数据库操作:

var magicTask = require('magic-task');
var mongoose = require('mongoose');
var User = mongoose.model('User');
var Comment = mongoose.model('Comment');

var queryUser = function(task) {
    task.promise = User.findOne(opts).exec();
};
var createUserIfNot = function(task, data) {
    if (data) {
        task.done(data);
    }
    else {
        var user = new User();
        user.save(task.send(user));
    }
};
var postComment = function(task, data) {
    var comment = new Comment({
        poster: data
    });
    comment.save(task.async);
};
// 依次执行上面的任务
magicTask.waterfall([queryUser, createUserIfNot, postComment]).then(function(data) {
    // 任务全部成功后的处理
    doSomething();
}).then(null, function(err) {
    console.log(err);
});

定义任务

magic-task的一个任务是一个如下形式的函数:

// 参数task是一个任务控制器,提供done、fail、promise、async方法,这在下面的内容中会具体介绍
// 参数data是任务接受的数据,取决于具体任务而定,例如waterfall任务中,每个任务的data是上一个任务的返回值,而each、map任务中data则是数组元素
// 任务执行完成后可以返回结果,用于某些执行方法的数据传递或是流程控制
function(task, data) {
    // 在这里定义任务
}

一共有3种任务类型:

便捷的异步任务

定义方式如下:

function asyncTask(task, data) {
    // 调用一个异步函数,例如fs.readfile
    // 如果异步函数的回调函数形式如function([err, ][arg1[, arg2[, arg3...]]]) {},
    // 即第一个参数为返回的错误,后面的为返回的数据,
    // 那么可以调用task.async方法,简单地处理数据并处理错误
    asyncFunction(dataArgs, task.async);

    // 定义成功后的数据处理函数(可以不写,默认返回data)
    task.done = function(data) {
        // 上面的异步函数asyncFunction执行成功后,可在这里写处理代码
        // data为获取到的数据
        // 如果上述的asyncFunction执行后的回调函数提供多个数据,则会合并到一个数组中,例如
        // asyncFunction(args, function(err, arg1, arg2) {})
        // 此时data为[arg1, arg2]
        return res; // 返回任务结果
    };
}

magic-task还提供另一个便捷的方法task.send(data)

function asyncTask(task) {
    // 这个方法默认asyncFunction的回调函数第一个参数为err,忽略其它参数
    // 如果没有错误,那么会将字符串'custom data'作为任务执行成功后的结果
    asyncFunction(dataArgs, task.send('custom data'));
}

Promise任务

定义方法与上述的异步任务有些相似:

function promiseTask(task, data) {
    task.promise = new Promise(function(resolve, reject) {
        if (something) {
            resolve(prData);
        }
        else {
            reject(new Error('msg'));
        }
    });

    // 定义成功后的数据处理函数(可以不写,默认返回data)
    task.done = function(data) {
        // data 等于 prData
        return res; //返回任务结果
    };
}

自定义任务

在一些特殊的异步或是同步过程时,可以使用更灵活的任务定义方式:

function customTask(task, data) {
    setTimeout(function() {
        if (something) {
            task.done(res); // 调用task.done方法表示任务成功,(参数表示任务结果,可选)
        }
        else {
            task.fail(new Error('msg')); // 调用task.fail方法使任务失败
        }
    });
}

注意

不要在重新定义task.done后再调用task.done(res)来表示任务成功并返回结果,例如:

function errorTask(task, data) {
    task.done = function(data) {};
    task.done(data); // 注意!!!这是错误的方法,任务并不会成功!!!
}

执行任务

定义好任务后,就可以使用magic-task的方法来执行了,magic-task可以顺序、并发、循环执行任务,还可以执行顺序或并发的数组遍历任务。magic-task提供以下的方法来执行任务:

这些方法都会返回一个Promise,这样可以组合使用,应对更复杂的异步流程。 如果没有特别说明,成功执行后获得的数据为最后一个任务返回的数据。

run(task, data)

执行单个任务,data为传递给这个任务的数据。

示例

var asyncTask = function(task, data) {
    task.done(data);
};
magicTask.run(asyncTask, 'input').then(function(data) {
    data.should.equal('input');
    done();
}, done);

waterfall(taskList)

顺序执行一系列任务,每个任务的返回结果为下一个任务function(task, data) {}中的参数data。如果taskList中的某个任务的返回���果为magicTask.end,则waterfall直接成功结束,不再执行其后面的任务。

示例

var task1 = function(task, data) { task.done('taskData_1'); };
var task2 = function(task, data) {
    console.log(data); // taskData_1
    task.done('taskData_2');
};
var task3 = function(task, data) {
    console.log(data); // taskData_2
    task.done('taskData_3');
};
magicTask.waterfall([task1, task2, task3]).then(function(res) {
    console.log(data); // taskData_3
}).then(null, function(err) {});

var task4 = function(task, data) { task.done(magicTask.end); };
var task5 = function(task, data) {
    // 不会执行该任务了
    task.done('taskData_5');
};
magicTask.waterfall([task4, task5]).then(function(res) {
    // 会执行这里的代码
}).then(null, function(err) {});

parallel(taskList)

并发执行一系列任务,所有任务都执行成功后才算成功,执行成功后的结果为一个数组。

示例

magicTask.parallel([taskA, taskB, taskC]).then(function(res) {
    // res[0]是taskA的结果, res[1]是taskB的结果,res[2]是taskC的结果
}).then(null, function(err) {});

each(array, iterTask)

执行遍历数组,迭代任务iterTask中function(task, data){}的data为数组元素,迭代任务会顺序执行,一个任务完成后才会进行下一个任务。

示例

var array = [1, 2, 3];
var iterTask = function(task, data) {
    console.log(data);
    task.done();
};
magicTask.each(array, iterTask).then(function(res) {}).then(null, function(err) {});
// 会依次输出1, 2, 3

map(array, iterTask)

执行遍历数组,迭代任务iterTask中function(task, data){}的data为数组元素,迭代任务会并发执行,所有任务都成功后才算执行成功,执行的结果为一个数组,类似于parallel方法。

示例

var array = [1, 2, 3];
var iterTask = function(task, data) {
    asyncFunction(function() {
        console.log(data);
        task.done(data - 1);
    });
};
magicTask.map(array, iterTask).then(function(res) {
    // res为[0, 1, 2]
    // 控制台输出1, 2, 3的顺序不可预测
}).then(null, function(err) {});

whilst(condTask, loopTask)

执行循环任务,第一个任务为条件判断,第二个任务为循环体,相当于while(cond) {body}

示例

var i = 0;
var condTask = function(task) {
    setTimeout(function() {
        task.done(i < 3);
    });
};
var loopTask = function(task, data) {
    console.log(data); // 依次输出undefined, 1, 2
    i++;
    task.done(i);
};
magicTask.whilst(condTask, loopTask).then(function(res) {
    // res为3
}).then(null, function(err) {});

doWhilst(loopTask, condTask)

执行循环任务,第一个任务为循环体,第二个任务为条件判断,相当于do {body} while(cond);,类似于whilst方法。

License

MIT