如何同步节点中的两个异步调用?
How to synchronize two asynchronous calls in node?
我在 Python 和 Javascript(在浏览器中)开发(业余级)。我逐渐接受并喜欢 JS 的异步特性,再加上它确实令人惊叹的反应式框架。
我现在尝试使用 NodeJS 来替换我服务器上的 Python 脚本。该程序的一般流程是获取 (HTTP) 一些 API,一旦我拥有所有这些 API,就可以做一些事情。这非常适合 Python,我只是连续调用并收集结果。性能和时间并不重要。
虽然 NodeJS 文档讨论了 blocking vs non-blocking code,但在我看来,浏览器中 JavaScript 的异步特性在 NodeJS 中非常常见。具体在我的例子中,fetch
到节点的端口是基于 Promises 的,需要通过环路才能使此类调用阻塞。
我应该如何同步我的调用以最终对所有收集的结果采取行动?我的代码类似于
fetch(urlOne)
.then(res => res.json())
.then(res => a = res.a)
fetch(urlTwo)
.then(res => res.json())
.then(res => b = res.b)
// here comes the moment when both a and b are to be used
我可以将一个 fetch
与另一个链接起来(在第一个 .then()
中),但这会分散脚本的主要机制:"get a
, get b
and the do something with them"). 具体来说,是否有类似Python的join()
等待线程结束(阻塞主线程)的东西?
请注意,我了解并欣赏浏览器中 JavaScript 的异步方法。有一个输出(渲染的DOM)感觉很自然,当一些元素可用时,它会异步更新。这对于后端服务(例如 Web 服务器)也很有用。不过,就我而言,活动是非常线性的(或者——这是我问题的核心——需要在某个时候同步)
您可以使用Bluebird.props方法。
const Bluebird = require('bluebird');
var allResponses = {
a: fetch(urlOne)
b: fetch(urlTwo)
};
Bluebird.props(allResponses)
.then(all => {
console.log(all.a);
console.log(all.b);
});
PS:Bluebird 与 Promises/A+ specs 兼容。这意味着您可以安全地使用它或代替内置 Promise class。
我通常在我的项目中用 Bluebird 覆盖 Promise class。
global.Promise = require('bluebird');
您可以使用Promise.all()
等待多个异步函数。
let firstAsync = fetch(urlOne)
.then(res => res.json())
.then(res => res.a)
let secondAsync = fetch(urlTwo)
.then(res => res.json())
.then(res => res.b)
Promise.all([firstAsync, secondAsync]).then(() => {
// here comes the moment when both a and b are to be used
)
简单地说,您可以将异步 npm 包与大量内容一起使用。它可以 运行 您的函数并行或同时执行,当所有函数完成后,将返回包含所有结果的最终回调。
执行此操作的正确方法确实是使用 Promise.all
,但不需要 then
具有副作用的调用(写入回调关闭的变量)。 all
以数组形式提供结果(与调用顺序相同)作为其解析值:
Promise.all([
fetch(urlOne)
.then(res => res.json())
.then(res => res.a) // <== No `a =` here
,
fetch(urlTwo)
.then(res => res.json())
.then(res => res.b) // <== No `b =` here
]).then(([a, b]) => { // <== Destructured parameter picking out the first
// and second entries of the array argument
// here comes the moment when both a and b are to be used
});
fetch
的替代示例:
// The `fetch` stand-in
function fetch(url) {
return new Promise(resolve => {
setTimeout(() => {
resolve({
json: () => new Promise(resolve => {
setTimeout(() => {
resolve({a: "a:" + url, b: "b:" + url});
}, url === "urlOne" ? 200 : 100);
})
});
}, 100);
});
}
// End of stand-in
Promise.all([
fetch("urlOne")
.then(res => res.json())
.then(res => res.a)
,
fetch("urlTwo")
.then(res => res.json())
.then(res => res.b)
]).then(([a, b]) => {
console.log(`a = ${a}, b = ${b}`);
});
我在 Python 和 Javascript(在浏览器中)开发(业余级)。我逐渐接受并喜欢 JS 的异步特性,再加上它确实令人惊叹的反应式框架。
我现在尝试使用 NodeJS 来替换我服务器上的 Python 脚本。该程序的一般流程是获取 (HTTP) 一些 API,一旦我拥有所有这些 API,就可以做一些事情。这非常适合 Python,我只是连续调用并收集结果。性能和时间并不重要。
虽然 NodeJS 文档讨论了 blocking vs non-blocking code,但在我看来,浏览器中 JavaScript 的异步特性在 NodeJS 中非常常见。具体在我的例子中,fetch
到节点的端口是基于 Promises 的,需要通过环路才能使此类调用阻塞。
我应该如何同步我的调用以最终对所有收集的结果采取行动?我的代码类似于
fetch(urlOne)
.then(res => res.json())
.then(res => a = res.a)
fetch(urlTwo)
.then(res => res.json())
.then(res => b = res.b)
// here comes the moment when both a and b are to be used
我可以将一个 fetch
与另一个链接起来(在第一个 .then()
中),但这会分散脚本的主要机制:"get a
, get b
and the do something with them"). 具体来说,是否有类似Python的join()
等待线程结束(阻塞主线程)的东西?
请注意,我了解并欣赏浏览器中 JavaScript 的异步方法。有一个输出(渲染的DOM)感觉很自然,当一些元素可用时,它会异步更新。这对于后端服务(例如 Web 服务器)也很有用。不过,就我而言,活动是非常线性的(或者——这是我问题的核心——需要在某个时候同步)
您可以使用Bluebird.props方法。
const Bluebird = require('bluebird');
var allResponses = {
a: fetch(urlOne)
b: fetch(urlTwo)
};
Bluebird.props(allResponses)
.then(all => {
console.log(all.a);
console.log(all.b);
});
PS:Bluebird 与 Promises/A+ specs 兼容。这意味着您可以安全地使用它或代替内置 Promise class。
我通常在我的项目中用 Bluebird 覆盖 Promise class。
global.Promise = require('bluebird');
您可以使用Promise.all()
等待多个异步函数。
let firstAsync = fetch(urlOne)
.then(res => res.json())
.then(res => res.a)
let secondAsync = fetch(urlTwo)
.then(res => res.json())
.then(res => res.b)
Promise.all([firstAsync, secondAsync]).then(() => {
// here comes the moment when both a and b are to be used
)
简单地说,您可以将异步 npm 包与大量内容一起使用。它可以 运行 您的函数并行或同时执行,当所有函数完成后,将返回包含所有结果的最终回调。
执行此操作的正确方法确实是使用 Promise.all
,但不需要 then
具有副作用的调用(写入回调关闭的变量)。 all
以数组形式提供结果(与调用顺序相同)作为其解析值:
Promise.all([
fetch(urlOne)
.then(res => res.json())
.then(res => res.a) // <== No `a =` here
,
fetch(urlTwo)
.then(res => res.json())
.then(res => res.b) // <== No `b =` here
]).then(([a, b]) => { // <== Destructured parameter picking out the first
// and second entries of the array argument
// here comes the moment when both a and b are to be used
});
fetch
的替代示例:
// The `fetch` stand-in
function fetch(url) {
return new Promise(resolve => {
setTimeout(() => {
resolve({
json: () => new Promise(resolve => {
setTimeout(() => {
resolve({a: "a:" + url, b: "b:" + url});
}, url === "urlOne" ? 200 : 100);
})
});
}, 100);
});
}
// End of stand-in
Promise.all([
fetch("urlOne")
.then(res => res.json())
.then(res => res.a)
,
fetch("urlTwo")
.then(res => res.json())
.then(res => res.b)
]).then(([a, b]) => {
console.log(`a = ${a}, b = ${b}`);
});