运行 与 promise 串联的异步函数
Running asynchronous functions in series with promises
我正在尝试 运行 使用 promises 串联多个异步任务。每个任务应该 运行 紧接在前一个任务完成之后。这是我尝试过的简化示例:
var order = [];
var tasks = [
new Promise(resolve => {
order.push(1);
setTimeout(() => {
order.push(2)
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(3);
setTimeout(() => {
order.push(4)
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(5);
resolve();
})
];
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
console.log(order); // [ 1, 3, 5 ]
});
setTimeout(() => console.log(order), 200); // [ 1, 3, 5, 2, 4 ]
我希望 order
在回调函数中等于 [ 1, 2, 3, 4, 5 ]
。但是我得到了那些奇怪的结果([ 1, 3, 5 ]
在 then
回调中,[ 1, 3, 5, 2, 4 ]
在延迟函数中)。我错过了什么?
你没有注意到当你使用 setTimeout
时,回调(push 2
、4
和 log order
)将被执行事件循环的下一次迭代,即下一次 'tick'。当所有其他函数(Promise
构造函数和 reduce
回调)正在 立即执行时 ,即在当前 'tick'.
var order = [];
var tasks = [
new Promise(resolve => {
order.push(1); // 1. callback executes immediately pushing 1 into order
setTimeout(() => { // 2. setTimeout executes, pushing the callback into the event queue after 100ms
order.push(2) // 8. callback executes, pushing 2 into order
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(3); // 3. callback executes immediately pushing 3 into order
setTimeout(() => { // 4. setTimeout executes, pushing the callback into the event queue after 100ms
order.push(4) // 9. callback executes, pushing 4 into order
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(5); // 5. callback executes immediately pushing 5 into order
resolve();
})
];
console.log(order); // [ 1, 3, 5 ]
// 6. reduce executes immediately, executes Promise.resolve which logs order and then loops through order and executes the callback everytime
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
console.log(order); // [ 1, 3, 5 ]
});
setTimeout(() => {
console.log(order); // 10. callback executes and logs order
}, 200); // 7. setTimeout executes, pushing the callback into the event queue after 200ms
只有 在 步骤 1 到 7 发生后,所有推入事件队列(由 setTimeout
)的回调将被执行,即推入调用堆栈,在上述回调执行后(步骤 8、9 和 10),清除事件队列并最终清除调用堆栈。
请注意,只有当调用堆栈为空时,函数才会从事件队列中弹出。
这是一种没有承诺且有点奇怪的做事方式,但它似乎有效:
"use strict";
var order = [];
var i = 0;
function next(){
if(tasks[++i]) tasks[i]()
}
var tasks = [
function() {
order.push(1);
setTimeout(() => {
order.push(2)
next()
}, 100);
},
function() {
order.push(3);
setTimeout(() => {
order.push(4)
next();
}, 100);
},
function() {
order.push(5);
next()
console.log(order)
}
];
tasks[0]()
当你写类似
的东西时
new Promise(resolve => {
order.push(1);
setTimeout(() => {
order.push(2)
resolve();
}, 100);
});
立即执行,这意味着它运行现在,并在 0.1 秒内解决。
你把它写在一个数组里没关系,函数现在仍然运行,并且承诺作为数组中的值返回。
换句话说,所有三个 promise 并行调用 运行,它们都立即 运行,相隔仅几毫秒,并在内部计时器的给定时间解析,从 现在!
如果你想 运行 一个接一个地承诺,它们必须以某种方式包装起来,这样它们就不会 运行 现在 ,但是无论何时他们被称为,例如
var tasks = [
_ => new Promise(resolve => {
order.push(1);
setTimeout(() => {
order.push(2)
resolve();
}, 100);
}),
_ => new Promise(resolve => {
order.push(3);
setTimeout(() => {
order.push(4)
resolve();
}, 100);
}),
_ => new Promise(resolve => {
order.push(5);
resolve();
}),
];
(对于匿名箭头函数,下划线在 ES2015 shorthand 中有效)
其中每个数组值都是一个可以调用的匿名函数,当调用 promise 构造函数时 运行s 和 returns promise。
要串行递归调用函数,递归函数调用是最简单的,当前函数完成后调用下一个函数等
(function iterate(i) {
tasks[i]().then(() => { // when done
if (tasks[++i]) iterate(i); // call the next one
});
})(0);
编辑:
你也可以Array.reduce
你已经在做的方式,现在你有returns承诺
的功能
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
// all done, chain is complete !
});
每个异步函数都有一个同步部分,即导致承诺的(同步)return 的设置。
我正在尝试 运行 使用 promises 串联多个异步任务。每个任务应该 运行 紧接在前一个任务完成之后。这是我尝试过的简化示例:
var order = [];
var tasks = [
new Promise(resolve => {
order.push(1);
setTimeout(() => {
order.push(2)
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(3);
setTimeout(() => {
order.push(4)
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(5);
resolve();
})
];
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
console.log(order); // [ 1, 3, 5 ]
});
setTimeout(() => console.log(order), 200); // [ 1, 3, 5, 2, 4 ]
我希望 order
在回调函数中等于 [ 1, 2, 3, 4, 5 ]
。但是我得到了那些奇怪的结果([ 1, 3, 5 ]
在 then
回调中,[ 1, 3, 5, 2, 4 ]
在延迟函数中)。我错过了什么?
你没有注意到当你使用 setTimeout
时,回调(push 2
、4
和 log order
)将被执行事件循环的下一次迭代,即下一次 'tick'。当所有其他函数(Promise
构造函数和 reduce
回调)正在 立即执行时 ,即在当前 'tick'.
var order = [];
var tasks = [
new Promise(resolve => {
order.push(1); // 1. callback executes immediately pushing 1 into order
setTimeout(() => { // 2. setTimeout executes, pushing the callback into the event queue after 100ms
order.push(2) // 8. callback executes, pushing 2 into order
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(3); // 3. callback executes immediately pushing 3 into order
setTimeout(() => { // 4. setTimeout executes, pushing the callback into the event queue after 100ms
order.push(4) // 9. callback executes, pushing 4 into order
resolve();
}, 100);
}),
new Promise(resolve => {
order.push(5); // 5. callback executes immediately pushing 5 into order
resolve();
})
];
console.log(order); // [ 1, 3, 5 ]
// 6. reduce executes immediately, executes Promise.resolve which logs order and then loops through order and executes the callback everytime
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
console.log(order); // [ 1, 3, 5 ]
});
setTimeout(() => {
console.log(order); // 10. callback executes and logs order
}, 200); // 7. setTimeout executes, pushing the callback into the event queue after 200ms
只有 在 步骤 1 到 7 发生后,所有推入事件队列(由 setTimeout
)的回调将被执行,即推入调用堆栈,在上述回调执行后(步骤 8、9 和 10),清除事件队列并最终清除调用堆栈。
请注意,只有当调用堆栈为空时,函数才会从事件队列中弹出。
这是一种没有承诺且有点奇怪的做事方式,但它似乎有效:
"use strict";
var order = [];
var i = 0;
function next(){
if(tasks[++i]) tasks[i]()
}
var tasks = [
function() {
order.push(1);
setTimeout(() => {
order.push(2)
next()
}, 100);
},
function() {
order.push(3);
setTimeout(() => {
order.push(4)
next();
}, 100);
},
function() {
order.push(5);
next()
console.log(order)
}
];
tasks[0]()
当你写类似
的东西时new Promise(resolve => {
order.push(1);
setTimeout(() => {
order.push(2)
resolve();
}, 100);
});
立即执行,这意味着它运行现在,并在 0.1 秒内解决。
你把它写在一个数组里没关系,函数现在仍然运行,并且承诺作为数组中的值返回。
换句话说,所有三个 promise 并行调用 运行,它们都立即 运行,相隔仅几毫秒,并在内部计时器的给定时间解析,从 现在!
如果你想 运行 一个接一个地承诺,它们必须以某种方式包装起来,这样它们就不会 运行 现在 ,但是无论何时他们被称为,例如
var tasks = [
_ => new Promise(resolve => {
order.push(1);
setTimeout(() => {
order.push(2)
resolve();
}, 100);
}),
_ => new Promise(resolve => {
order.push(3);
setTimeout(() => {
order.push(4)
resolve();
}, 100);
}),
_ => new Promise(resolve => {
order.push(5);
resolve();
}),
];
(对于匿名箭头函数,下划线在 ES2015 shorthand 中有效)
其中每个数组值都是一个可以调用的匿名函数,当调用 promise 构造函数时 运行s 和 returns promise。
要串行递归调用函数,递归函数调用是最简单的,当前函数完成后调用下一个函数等
(function iterate(i) {
tasks[i]().then(() => { // when done
if (tasks[++i]) iterate(i); // call the next one
});
})(0);
编辑:
你也可以Array.reduce
你已经在做的方式,现在你有returns承诺
tasks.reduce((cur, next) => cur.then(next), Promise.resolve()).then(() => {
// all done, chain is complete !
});
每个异步函数都有一个同步部分,即导致承诺的(同步)return 的设置。