将对象/变量从异步函数移开 [英] Move object/variable away from async function

查看:86
本文介绍了将对象/变量从异步函数移开的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这是一个基本问题,但我自己无法弄明白,如何从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);
返回await response.json();
} catch(错误){
console.log(error);
}
};
getData(url).then(function(result){//promise.pending w / o .then
let x = result; //这里是我要导出的真正的JSON
});
}
console.log(x); // -element未导出:(


解决方案

这里有一些您可能希望尝试更清洁的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('总失败!');
console.log(错误);
});

它是如何工作的?



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




  • 获取URL

  • 提取JSON响应



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



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



你是否接受它,我提出它作为同一问题的另一种观点,解决了我认为最优雅和清晰的方式。






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



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



这种模式不仅使基本变量作用域复杂化,这是您主要关注的问题,还有如何最好地表达复杂工作流程的问题,这些工作流程通常是阻塞和非阻塞语句的混合。如果做异步工作需要以函数的形式提供许多延续,那么我们就知道做这项工作将是一场持续的战斗,以防止一百万个小函数的扩散,一百万个需要名称必须独特和清晰的东西。这是一个无法用库解决的问题。它需要根据变化的地形调整一个人的风格。



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


I understand that this is a basic question, but I can't figure it out myself, how to export my variable "X" (which is actually a JSON object) out of "for" cycle. I have tried a various ways, but in my case function return not the JSON.object itself, but a "promise.pending".

I guess that someone more expirienced with this will help me out. My code:

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 :(

解决方案

Here's some cleaner ES6 code you may wish to try:

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);
});

How does it work?

Using Array.map, it transforms the list of servers into a list of promises which are executed in parallel. Each promise does two things:

  • fetch the URL
  • extract JSON response

If either step fails, that one promise rejects, which will then cause the whole series to reject immediately.

Why do I think this is better than the accepted answer? In a word, it's cleaner. It doesn't mix explicit promises with async/await, which can make asynchronous logic muddier than necessary. It doesn't import the fetch library on every loop iteration. It converts the server URL to a string explicitly, rather than relying on implicit coercion. It doesn't create unnecessary variables, and it avoids the needless for loop.

Whether you accept it or not, I offer it up as another view on the same problem, solved in what I think is a maximally elegant and clear way.


Why is this so hard? Why is async work so counterintuitive?

Doing async work requires being comfortable with something known as "continuation passing style." An asynchronous task is, by definition, non-blocking -- program execution does not wait for the task to complete before moving to the next statement. But we often do async work because subsequent statements require data that is not yet available. Thus, we have the callback function, then the Promise, and now async/await. The first two solve the problem with a mechanism that allows you to provide "packages" of work to do once an asynchronous task is complete -- "continuations," where execution will resume once some condition obtains. There is absolutely no difference between a boring node-style callback function and the .then of a Promise: both accept functions, and both will execute those functions at specific times and with specific data. The key job of the callback function is to act as a receptacle for data about the asynchronous task.

This pattern complicates not only basic variable scoping, which was your main concern, but also the issue of how best to express complicated workflows, which are often a mix of blocking and non-blocking statements. If doing async work requires providing lots of "continuations" in the form of functions, then we know that doing this work will be a constant battle against the proliferation of a million little functions, a million things needing names that must be unique and clear. This is a problem that cannot be solved with a library. It requires adapting one's style to the changed terrain.

The less your feet touch the ground, the better. :)

这篇关于将对象/变量从异步函数移开的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆