js jquery 异步 回调 Deferred promise 地狱回调 地狱 回调
说到js的异步就会让我想到使用requirejs和jquery的$.ajax,和HTML5的异步,之前都有介绍过可以参阅:
《jquery内置异步功能简单使用》 《html5异步》 《requirejs教程》 《requirejs模块管理插件简单介绍及案例》
IE 6+
Opera 15+
Safari 5+
Chrome 30+
Firefox 3.6.28+
async.js是为nodejs开发出来的异步编程模块,但是也可以直接用于网页中使用,兼容性可以支持IE6以上。
如果要在nodejs上使用就安装
下载:async.rar
npm install async
<script src="async.min.js"></script>
举两个简单例子:
//同步,只有当前面的函数执行完成后,后面的函数才能执行,都执行完成后才回调成功函数, 如果中途有错误被激活后面的函数也不会执行,立马回调出错误的函数。 async.series([ function (fn) { setTimeout(function () { $('div').css({ 'background': 'red' }); fn(null); //在同步时,设置null表示成功,下面的步骤才会执行,null以外的内容表示错误 }, 3000); }, function (fn) { console.log(2); fn(null); }], function (err, sucess) { if (err) { document.title = '出错,没全部都执行'; } else if (sucess) { document.title = '成功,全部都执行了'; } }); 作用就是为某个函数添加回调函数,这个其实在jquery也能实现。
//each //异步,不管之前的函数有没有执行,后面的函数也能先执行,都执行完成后才进行回调 var items = [ function (callback) { setTimeout(function () { alert(1); callback() }, 2000); }, function (callback) { alert(2); callback() } ]; async.each(items, function (item, callback) { (item)(callback); }, function () { alert('都执行了'); }); -------------------------------------------------------------------------------------- //异步,eachLimit当作是each的加强版,只是添加了一个limit参数也就是允许同时执行函数的进程数量 //在没有出错的情况下,下面的例子弹出的顺序是 2,3,1,5,4 //你可以理解为一个厕所有2个公共坑位,1和2同时进,3,4,5后面等。2立马就出来,1还迟迟没出来, //2的位置就让3给用了,3也立马出来,接着4进去,这时刻4和1同时在里面。1终于出来了, //5立马进去也立马出来,最后4也出来了。 //某个函数中激活错误函数,后面的函数不会运行,错误回调立马被执行 async.eachLimit([ function (callback) { setTimeout(function () { alert(1); callback() }, 4000); }, function (callback) { alert(2); callback() }, function (callback) { alert(3); callback() }, function (callback) { setTimeout(function () { alert(4); callback() }, 5000); }, function (callback) { alert(5); callback() } ],2, function (item, callback) { (item)(callback); }, function (err) { if (err) { alert('有错误到此为止'); } else { alert('都执行完成了'); } }); -------------------------------------------------------------------------------- //eachSeries //和each有2点不同, //1,eachSeries是同步的 //2,一旦某一个函数中的错误被激活,此函数的后面其他函数就不会执行 async.eachSeries([ function (callback) { setTimeout(function () { alert(1); callback() }, 2000); }, function (callback) { alert(2); callback() }, function (callback) { alert(3); callback() } ], function (item, callback) { (item)(callback); }, function (err) { if (err) { alert('有错误到此为止'); } else { alert('都执行完成了'); } });
// 同步,上一个函数可以传值给下一个函数使用,如果某一个函数错误激活后面的函数也不能执行,之后就是回调
//waterfall 的 tasks 参数只能是数组类型
async.waterfall([
function (callback) {
callback(null, 'one', 'two');
},
function (arg1, arg2, callback) { //上面的callback传2个参数,要接受的话就设置2个参数
console.log(arg1 + '--' + arg2); // one--two
callback(null, 'three','fff','4444');
},
function (arg1, arg2, arg3, callback) {//上面的callback传3个参数,要接受的话就设置3个参数
console.log(arg1 + '--' + arg2 + '--' + arg3); //three--fff--4444
callback(null, 'done');
}
], function (err, result) {
if (err) {
alert('有错误' + err);
} else {
alert('都执行了' + result);
}
});
//如果希望第一个函数也能接收到其他值的话可以这么写
async.waterfall([
async.apply(myFirstFunction, 'zero'),
mySecondFunction,
myLastFunction,
], function (err, result) {
// result now equals 'done'
});
function myFirstFunction(arg1, callback) {
// 第一个函数接收到zero参数
callback(null, 'one', 'two');
}
function mySecondFunction(arg1, arg2, callback) {
callback(null, 'three');
}
function myLastFunction(arg1, callback) {
callback(null, 'done');
}
//异步,如果没激活错误返回的结果是 one,two,thress,thress 是按照之前的顺序排序的, //跟执行的时间顺序无关。 //如果某个函数有激活错误,错误的回调立马执行,后面的函数依然执行。 async.parallel([ function (callback) { callback(null, 'one'); }, function (callback) { console.log(22); callback(null, 'two'); }, function (callback) { console.log(33); callback(null, 'thress'); }, function (callback) { console.log(44); callback(null, 'thress'); }], function (err, results) { if (err) { console.log('错误:'+err); } else { console.log('成功:' + results); } });
//批量修改数组内容,功能跟jquery中的map一样
async.map(['file1', 'file2', 'file3'], function (item, callback) {
console.log(item); // file1,file2,file3
callback(null, item + 1);
}, function (err, results) {
if (err) {
console.log(err);
} else if (results) {
console.log(results); // ["file11", "file21", "file31"]
}
});
扩展功能
mapSeries(arr, iteratee, [callback])
mapLimit(arr, limit, iteratee, [callback])
//效果就是类似for循环完了之后就回调一个函数
var count = 0;
async.during(
function (callback) {
// console.log('当count等于' + count+'时,执行了一些代码'); //代码放这里执行了6次
return callback(null, count < 5);
},
function (callback) {
count++;
// console.log('当count等于' + count + '时,执行了一些代码'); //代码放这里执行了5次(推荐放这里)
document.title = count;
setTimeout(callback, 1000);
// console.log(count);
},
function (err,sucess) { //第六秒时候执行回调
if (err) { } else { document.title = 'for循环成功后回调'; }
}
);
//类似for循环,创建对象
var arr = [];
function createUser(id, callback) {
callback(null, { //这里写的对象就是我们要循环创建的
id: 'user' + id
})
}
// generate 5 users
async.times(5, function (n, next) {
createUser(n, function (err, user) {
console.log(n); //索引
console.log(user); //对象
next(err, user)
})
}, function (err, users) {
arr = users;
});
console.log(arr);
//同步,设置为1 任意一个函数错误激活后面程序仍然可以运行,都运行完成后回调
//异步,设置>1的数字 任意一个函数错误激活后面程序仍然可以运行,都运行完成后回调
var q = async.queue(function (task, callback) {
//q.length() //返回还有多少个正在等待的要执行的函数,假如有3个进程,第一个函数必须先执行后才能执行到它,因为他查询的是等待的函数。
// console.log(q.started); //判断我们定义的这个q对象是否已经开始执行整个程序,true是这个整个程序开始执行了。
if (task.name == '工人1') {
setTimeout(function () {
console.log('hello ' + task.name);
callback(1);
}, 3000)
} else if (task.name == '工人2') {
setTimeout(function () {
console.log('hello ' + task.name);
callback(1);
}, 3000)
} else {
console.log('hello ' + task.name);
callback();
}
},2); //这里设置并发数有2以上的就是异步了,如果没设置默认就是1,也就是同步了
q.drain = function () { //所有的程序都执行完,而且不管成不成功都要执行这里
console.log('最后这里总要执行');
// console.log(q.idle()); //默认是false说明程序在执行,如果为true说明程序已经结束了。
}
q.empty = function () { //总是在最后一个函数执行完成之前执行。例如,有3个函数,在前2个函数执行完成后就立马执行。
console.log('总是在最后一个函数执行完成之前执行');
// console.log(q.idle()); //默认是false说明程序在执行,如果为true说明empty程序已经结束了。
}
q.push({ name: '工人1' }, function (err) {
if (err) {
console.log('工人1 没完成'); //单进程失败回调
//ill(); //在此代码后面的所有函数都不会执行,包括q.drain
//.pause() //此代码后面的,函数暂时停止运行
//q.paused //true,表示程序暂停 false,表示没暂停
// setTimeout(function () { q.resume() }, 13000); //13秒后恢复 q.pause和q.resume配合使用
} else {
console.log('工人1 完成'); //单进程成功回调
}
});
q.push({ name: '工人2' }, function (err) {
if (err) {
console.log('工人2 没完成');
} else {
console.log('工人2 完成');
}
});
q.push({ name: '工人3' }, function (err) {
if (err) {
console.log('工人3 没完成');
} else {
console.log('工人3 完成');
}
});
https://github.com/caolan/async
http://www.easyui.info/archives/1788.html
https://cnodejs.org/topic/54acfbb5ce87bace2444cbfb