Javascript 然后阻塞isn';不要被连锁反应的承诺所束缚

Javascript 然后阻塞isn';不要被连锁反应的承诺所束缚,javascript,es6-promise,Javascript,Es6 Promise,我正在用JS重试一些异步调用。简化并重写为setTimeout时,逻辑如下所示: let error=true 让承诺=无效 const runPromise=(值)=>新承诺((res)=>{ 如果(!错误){ res() 返回 } 如果(承诺){ 回报承诺。然后(()=>{ 返回runPromise(值) }) } 承诺=新承诺((res2)=>{ 设置超时(()=>{ 承诺=无效 console.log(值) 错误=错误 res2() }, 1000) }).然后(()=>res())

我正在用JS重试一些异步调用。简化并重写为
setTimeout
时,逻辑如下所示:

let error=true
让承诺=无效
const runPromise=(值)=>新承诺((res)=>{
如果(!错误){
res()
返回
}
如果(承诺){
回报承诺。然后(()=>{
返回runPromise(值)
})
}
承诺=新承诺((res2)=>{
设置超时(()=>{
承诺=无效
console.log(值)
错误=错误
res2()
}, 1000)
}).然后(()=>res())
})
runPromise(1).then(()=>{console.log(1)})
runPromise(2).then(()=>{console.log(2)})

runPromise(3)。然后(()=>{console.log(3)})
您的问题是在
if(promise)
情况下,
runPromise
返回的承诺永远不会
res()
得到解决<代码>返回从executor回调调用不会执行任何操作。你可以通过这样做来解决这个问题

const runPromise = (value) => new Promise((res) => {
    if (!error) {
        console.log("resolve immediately without error")
        res()
    } else if (promise) {
        promise.then(() => {
            console.log("resolve after waiting for previous promise")
            res(runPromise(value))
        })
    } else {
        promise = new Promise((res2) => {
            setTimeout(() => {
                promise = null
                error = false
                res2()
                console.log("resolve after timeout")
                res()
            }, 1000)
        })
    }
})
但是你真的应该避免这个错误,因为它首先导致了这个错误。不要调用
然后
新承诺
运行承诺()!改用

let error=true
让承诺=无效
函数runPromise(值){
如果(!错误){
console.log(值“立即解析,无错误”)
返回承诺。解决();
}否则,如果(承诺){
console.log(值“延迟到承诺”)
//现在这个“return”按预期工作
回报承诺。然后(()=>{
console.log(值“重试”)
返回runPromise(值)
})
}否则{
console.log(值“启动超时”)
承诺=新承诺(res2=>{
设置超时(res2,1000)
}).然后(()=>{
承诺=无效
错误=错误
日志(值“等待超时”)
});
回报承诺;
}
}
runPromise(1).then(()=>{console.log(1)})
runPromise(2).then(()=>{console.log(2)})

runPromise(3)。然后(()=>{console.log(3)})
您的问题是在
if(promise)
情况下,
runPromise
返回的承诺永远不会
res()
得到解决<代码>返回
从executor回调调用不会执行任何操作。你可以通过这样做来解决这个问题

const runPromise = (value) => new Promise((res) => {
    if (!error) {
        console.log("resolve immediately without error")
        res()
    } else if (promise) {
        promise.then(() => {
            console.log("resolve after waiting for previous promise")
            res(runPromise(value))
        })
    } else {
        promise = new Promise((res2) => {
            setTimeout(() => {
                promise = null
                error = false
                res2()
                console.log("resolve after timeout")
                res()
            }, 1000)
        })
    }
})
但是你真的应该避免这个错误,因为它首先导致了这个错误。不要调用
然后
新承诺
运行承诺()!改用

let error=true
让承诺=无效
函数runPromise(值){
如果(!错误){
console.log(值“立即解析,无错误”)
返回承诺。解决();
}否则,如果(承诺){
console.log(值“延迟到承诺”)
//现在这个“return”按预期工作
回报承诺。然后(()=>{
console.log(值“重试”)
返回runPromise(值)
})
}否则{
console.log(值“启动超时”)
承诺=新承诺(res2=>{
设置超时(res2,1000)
}).然后(()=>{
承诺=无效
错误=错误
日志(值“等待超时”)
});
回报承诺;
}
}
runPromise(1).then(()=>{console.log(1)})
runPromise(2).then(()=>{console.log(2)})

runPromise(3)。然后(()=>{console.log(3)})
这里或多或少有无限的递归。一旦您第一次设置了
promise=
if(promise)
将始终进入,并且它将始终附加另一个
。然后,
回调,在调用时,只会反复执行相同的函数。它也不会调用
res()

我通常会在这里分离关注点:让一个函数构建承诺链,并让它接受一个任务函数,该函数使用提供的值进行调用:

 let queue = Promise.resolve(); // no need for null, let it always be a promise

 function runTask(task, ...args) {
  return queue = queue.then(() => task(...args));
 }
然后编写另一个表示任务的函数,例如,在您的情况下,它是一个等待勾号的函数:

 function waitTask(n) { return new Promise(res => setTimeout(res, 1000, n)); }

runTask(waitTask, 1);
runTask(waitTask, 2);
let queue=Promise.resolve();
函数runTask(任务,…参数){
return queue=queue.then(()=>task(…args));
}
函数waitTask(n){返回新承诺(res=>setTimeout(res,1000,n));}
runTask(waitTask,1)。然后(console.log);

runTask(waitTask,2)。然后(console.log)这里或多或少有无限的递归。一旦您第一次设置了
promise=
if(promise)
将始终进入,并且它将始终附加另一个
。然后,
回调,在调用时,只会反复执行相同的函数。它也不会调用
res()

我通常会在这里分离关注点:让一个函数构建承诺链,并让它接受一个任务函数,该函数使用提供的值进行调用:

 let queue = Promise.resolve(); // no need for null, let it always be a promise

 function runTask(task, ...args) {
  return queue = queue.then(() => task(...args));
 }
然后编写另一个表示任务的函数,例如,在您的情况下,它是一个等待勾号的函数:

 function waitTask(n) { return new Promise(res => setTimeout(res, 1000, n)); }

runTask(waitTask, 1);
runTask(waitTask, 2);
let queue=Promise.resolve();
函数runTask(任务,…参数){
return queue=queue.then(()=>task(…args));
}
函数waitTask(n){返回新承诺(res=>setTimeout(res,1000,n));}
runTask(waitTask,1)。然后(console.log);

runTask(waitTask,2)。然后(console.log)可能是因为您正在变异所有人共享的相同的
承诺
,请避免@费德肯是的,这很有道理。你知道我怎样才能把它们连接起来,这样链子就不会断了吗?我们的想法是将对这个
runPromise
函数的任何后续调用推迟到第一个调用finishes@Federkun实际上,变异全局
promise
error
变量似乎是此函数的全部目的?@Bergi yes,很可能是因为你改变了所有人共享的相同的
承诺
,避免这种情况@费德肯是的,这很有道理。有吗