即使javascript在单线程中运行,异步函数中仍可能出现并发问题。其中一些可以通过大大增加代码的复杂性来避免,但有些我像这样解决:
// private "lock"
let _lock = null;
// this function waits till the last call is done, then
// initiates next one
async function doTheStuff() {
while (_lock) {
await _lock;
}
_lock = actuallyDoTheStuff();
const result = await _lock;
_lock = null;
return result;
}
async function actuallyDoTheStuff() {
// this function really does the stuff
}
这可确保只有一个actuallyDoTheStuff
实例正在运行,但它看起来并不那么好。
这真的行得通吗?我能确定不会有无休止的循环/锁定吗?
而且,无论它是否有效,难道没有更好的方法来做到这一点吗?
我会将所有内容封装在 actuallyDoTheStuff
中,它只是在它生成的最后一个 Promise 上调用 .then
:
const actuallyDoTheStuff = (() => {
let lastProm = Promise.resolve();
return () => {
const nextProm = lastProm.then(() => {
return new Promise(resolve => setTimeout(() => {
console.log('resolving');
resolve();
}, 1000));
});
lastProm = nextProm;
return lastProm;
};
})();
console.log('start');
actuallyDoTheStuff();
actuallyDoTheStuff();
actuallyDoTheStuff();
setTimeout(() => {
actuallyDoTheStuff();
actuallyDoTheStuff();
}, 200);
如果可能会抛出,则在重新分配给lastProm
时添加一个catch
const actuallyDoTheStuff = (() => {
let lastProm = Promise.resolve();
return () => {
const nextProm = lastProm.then(() => {
return new Promise(resolve => setTimeout(() => {
console.log('resolving');
resolve();
}, 1000));
});
lastProm = nextProm.catch(() => null);
return nextProm;
};
})();
console.log('start');
actuallyDoTheStuff();
actuallyDoTheStuff();
actuallyDoTheStuff();
setTimeout(() => {
actuallyDoTheStuff();
actuallyDoTheStuff();
}, 200);
我不确定actuallyDoTheStuff
最终应该做什么,但是如果您尝试对它的多个调用进行排序(并等待每次调用(,您可以doTheStuff
一个异步包装器函数,其中包含在每次迭代时等待actuallyDoTheStuff
for loop
:
function actuallyDoTheStuff( iteration ) {
console.log( "Waiting...")
return new Promise( res => {
setTimeout( () => {
res( iteration );
}, 150 );
} );
}
async function doTheStuff() {
for ( let i = 0; i <= 5; i++ ) {
const result = await actuallyDoTheStuff( i );
console.log( result );
}
}
doTheStuff();
或者actuallyDoTheStuff
做一个递归函数:
let index = 1;
async function actuallyDoTheStuff( i ) {
if ( i <= 5 ) {
console.log( "Waiting..." )
await new Promise( res => {
setTimeout( () => {
console.log( i );
i++
res();
actuallyDoTheStuff( i );
}, 150 );
} );
}
}
actuallyDoTheStuff( index );