将对象/变量从异步函数移开

时间:2018-01-07 05:11:28

标签: javascript json node.js

我知道这是一个基本问题,但我自己无法弄明白,如何从“for”循环中导出我的变量“X”(实际上是一个JSON对象)。我尝试了各种方法,但在我的情况下,函数返回的不是JSON.object本身,而是“promise.pending”。

我想那个更有经验的人会帮助我。我的代码:

for (let i = 0; i < server.length; i++) {
    const fetch = require("node-fetch");
    const url = ''+(server[i].name)+'';
    const getData = async url => {
        try {
            const response = await fetch(url);
            return await response.json();
        } catch (error) {
        console.log(error);
        }
    };
    getData(url).then(function(result) { //promise.pending w/o .then
        let x = result; //here is real JSON that I want to export
    });
 }
 console.log(x); // -element is not exported :(

2 个答案:

答案 0 :(得分:3)

您可以尝试使用一些更干净的ES6代码:

const fetch = require("node-fetch");

Promise.all(
    server.map((srv) => {
        const url = String(srv.name);

        return fetch(url)
        .then((response) => response.json())
        .catch((err) => console.log(err));
    })
)
.then((results) => {
    console.log(results);
})
.catch((err) => {
    console.log('total failure!');
    console.log(err);
});

它是如何运作的?

使用Array.map,它将服务器列表转换为并行执行的promise列表。每个承诺都做两件事:

  • 获取网址
  • 提取JSON响应

如果任一步骤失败,那一个承诺拒绝,这将导致整个系列立即拒绝。

为什么我认为这比接受的答案更好?总之,它更干净。它没有将显式的promises与async / await混合在一起,这可能使异步逻辑变得比必要的更混乱。它不会在每次循环迭代中导入fetch库。它明确地将服务器URL转换为字符串,而不是依赖于隐式强制。它不会创建不必要的变量,它可以避免不必要的for循环。

无论你是否接受,我都将其视为对同一问题的另一种看法,我认为这是一种最优雅,最清晰的方式。

为什么这么难?为什么异步工作如此违反直觉?

做异步工作需要对称为&#34;继续传递风格的事情感到满意。&#34;根据定义,异步任务是非阻塞的 - 在移动到下一个语句之前,程序执行不会等待任务完成。但我们经常进行异步工作,因为后续语句需要尚未提供的数据。因此,我们有回调函数,然后是Promise,现在是async / await。前两个解决问题的机制允许您提供&#34;包&#34;异步任务完成后要做的工作 - &#34; continuation,&#34;一旦条件获得,执行将恢复的地方。枯燥的节点式回调函数和Promise的.then之间完全没有区别:两者都接受函数,并且两者都将在特定时间和特定数据执行这些函数。回调函数的关键任务是充当异步任务数据的容器。

这种模式不仅使基本变量范围变得复杂,这是您主要关注的问题,也是如何最好地表达复杂工作流的问题,这些工作流通常是阻塞和非阻塞语句的混合。如果做异步工作需要提供大量的继续&#34;以功能的形式,我们知道做这项工作将是一场持续的战斗,反对一百万个小功能的扩散,一百万个需要名称必须独特和清晰的东西。这是一个无法用库解决的问题。它需要根据变化的地形调整一种风格。

你的双脚触地越少越好。 :)

答案 1 :(得分:2)

Javascript建立在承诺的概念之上。当你要求getData完成它的工作时,说的是,“好的,这需要一些时间,但我保证在工作完成后我会通知你。所以请相信我的承诺,一旦工作完成,我会告诉你“,它会立即给你一个承诺。

这就是你所看到的promise.pending。它尚未完成,因为尚未完成。现在,您应该使用getData的承诺注册某个任务(或函数),以便在完成工作时调用。

function doSomething(){
var promiseArray = [];
for (let i = 0; i < server.length; i++) {
    const fetch = require("node-fetch");
    const url = ''+(server[i].name)+'';
    const getData = async url => {
        try {
            const response = await fetch(url);
            return await response.json();
        } catch (error) {
        console.log(error);
        }
    };
    promiseArray.push(getData(url)); // keeping track of all promises
 }

 return Promise.all(promiseArray); //see, I'm not registering anything to promise, I'm passing it to the consumer

}

function successCallback(result) {
  console.log("It succeeded with " + result);
}

function failureCallback(error) {
  console.log("It failed with " + error);
}

let promise = doSomething(); // do something is the function that does all the logic in that for loop and getData
promise.then(successCallback, failureCallback);