Move object/variable away from async function

后端 未结 2 1846
故里飘歌
故里飘歌 2021-01-28 18:34

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 tri

相关标签:
2条回答
  • 2021-01-28 19:06

    Javascript builds on the concept of promises. When you ask getData to to do its work, what is says is that, "OK, this is going to take some time, but I promise that I'll let you know after the work is done. So please have faith on my promise, I'll let you know once the work is complete", and it immediately gives you a promise to you.

    That's what you see as promise.pending. It's pending because it is not completed yet. Now you should register a certain task (or function) with that promise for getData to call when he completes the work.

    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);
    
    0 讨论(0)
  • 2021-01-28 19:18

    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. :)

    0 讨论(0)
提交回复
热议问题