缘起
没理解js异步的同学看下面的例子:
for (var i = 0; i < 5; i++) {
//模拟一个异步操作 setTimeout(() => { console.log(i); }, 1000); }
我们想要的结果是:0,1,2,3,4
结果却出乎意料:5,5,5,5,5
分析
js的特点就是单线程异步非堵塞。需要好好理解这句话:js对于异步操作,不会停下来等待上一个异步操作完成,才进行下一个异步操作。
如果要达到顺序执行,只能用回调:也就是上一个异步操作完成时,再调用下一个异步操作。
要是如上面的循环,要如何操作呢?
解决方法1
通过调用自身解决循环的回调嵌套问题
function sync(i) { setTimeout(() => { if (i < 5){ console.log(i); i++; sync(i); } }, 1000); } sync(0)
解决方法2
使用await/async
优点:直观,符合同步编程思维。其实本质还是异步回调
缺点:大部分浏览器下载还不支持。需要配合Promise使用,需要写成两个函数
服务器端node.js支持。以下代码在最新版chrome浏览器中可以运行:
const f = (i) => { return new Promise((resolve, reject) => { setTimeout(() => { resolve(i); }, 1000); }); }; const testAsync = async () => { for (var i = 0; i < 5; i++) { const t = await f(i); console.log(t); } }; testAsync();
解决方法3
使用co库
function* useco(){ for(var i=0; i<5; i++){ yield new Promise((resolve, reject) => { setTimeout(() => { resolve(i); console.log(i); }, 1000); }); } } co(useco);
依赖于上一个异步操作的结果,进行下一个异步操作:
function* useco() { var x=0; for (var i = 0; i < 5; i++) { x= yield new Promise((resolve, reject) => { setTimeout(() => { resolve(x+i); }, 1000); }); console.log(x); } }
co(useco).then(() => {
console.log('执行完毕');
})
co还是很强大的。
解决方法4
等待补充...