将数据从数组映射到Promises并在Promise.all()上执行代码不起作用

时间:2016-11-18 16:20:40

标签: javascript promise

我有一个像这样的数组

let array =[ {message:'hello'}, {message:'http://about.com'}, {message:'http://facebook.com'}]

我想循环遍历它,在每个项目中,我向服务器发出请求以获取打开的图形数据,然后将获取的数据保存回数组。预期结果

array =[ 
    {message:'hello'}, 
    {message: {
            url:'http://about.com', title:'about'
        }
    }, 
    {message:{
            url:'http://facebook.com', title:'facebook'
        }
    }
]

我需要在异步完全完成后执行其他操作。下面的代码是我认为的

let requests = array.map( (item) => {
    return new Promise( (resolve) => {
        if (item.message.is('link')) {
            axios.get(getOpenGraphOfThisLink + item.message)
            .then( result => {
                item.message =result.data
                // console.log(item.message)
                // outputs were
                //{url:'http://about.com', title:'about'}
                //{url:'http://facebook.com', title:'facebook'}
                resolve()
            })

        }
    })
})

Promise.all(requests).then( (array) => {
    // console.log (array)
    // nothing output here
})

promise.all()将无法运行。 console.log(array)不会输出任何内容。

1 个答案:

答案 0 :(得分:3)

我看到该代码存在三个主要问题:

  1. 重要的是,您只有有时解决您在map回调中创建的承诺;如果item.message.is('link')为假,您永远不会做任何事情来解决。因此,Promise.all承诺永远不会解决。

  2. 您已接受array作为Promise.all then回调的参数,但它不会成为一个(或者更确切地说,不是有用的)一个)。

  3. 您未能通过axios来电处理失败的可能性。

  4. 如果我们通过对数组进行预过滤来解决#2问题,那么当您已经有一个承诺时,您就会创建第四个问题。

    相反:

    let array = /*...*/;
    let requests = array.filter(item => item.message.is('link'))
        .map(item => axios.get(getOpenGraphicOfThisLink + item.message)
            .then(result => {
                item.message = result.data;
                return result;
            })
        );
    
    Promise.all(requests).then(
        () => {
            // Handle success here, using `array`
        },
        error => {
            // Handle error
        }
    );
    

    请注意重用axios承诺会自动将错误传播到链中(因为我们不会向thencatch回调提供第二次回调。)

    示例(不会显示axios.get的错误,但......):

    
    
    // Apparently you add an "is" function to strings, so:
    Object.defineProperty(String.prototype, "is", {
      value(type) {
        return type != "link" ? true :  this.startsWith("http://");
      }
    });
    
    // And something to stand in for axios.get
    const axios = {
      get(url) {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve({data: "Data for " + url});
          }, 10);
        });
      }
    };
    
    // The code:
    let array =[ {message:'hello'}, {message:'http://about.com'}, {message:'http://facebook.com'}]
    let requests = array.filter(item => item.message.is('link'))
        .map(item => axios.get(/*getOpenGraphicOfThisLink + */item.message)
            .then(result => {
                item.message = result.data;
                return result;
            })
        );
    
    Promise.all(requests).then(
        () => {
            // Handle success here, using `array`
            console.log(array);
        },
        error => {
            // Handle error
            console.log(error);
        }
    );