Promise.All - 承诺内的承诺未得到解决

时间:2017-08-29 02:51:53

标签: javascript promise

您好我正在继续学习承诺,并且正在努力如何正确使用Promise.All或者我是否应该在这种情况下使用它。

我正在连接数据源并解析我对数组的第一个承诺。之后,我想获取这些结果,并在结果中使用另一个promise循环,并为使用外部API调用的数组添加另一个值。

经过研究后听起来好像我需要使用Promise.All以便在返回我的响应之前完成promises但是我仍然会在我添加到我的数组而不是期望值的值上获得挂起状态。我再次学习节点和承诺,所以我的方法可能完全有缺陷,在这种情况下,我愿意接受任何关于更好地做我想要完成的事情的建议。

function GetSearches(req, res) { 

    var BingSearches = new Promise((resolve, reject) => {
        GetBingSearches().toArray((err, response)=>{
            resolve(response);
        });          
    }) /* get data from external data source example data: [{SearchTerm: "Boxing", id: '4c142f92-ba6d-46af-8dba-cb88ebabb94a', CreateDate: '2017-08-10T13:59:20.534-04:00'}] */


    var GetSearchesWithImageUrl = BingSearches.then((response,reject) =>{
        for(var i in response){
            response[i].Image = new Promise((resolve, reject) => { 
                Bing.images(response[i].SearchTerm, {
                count: 1
                }, (err,res,body) => {
                    const bingImageUrl = body.value[0].contentUrl;
                    console.log(bingImageUrl) // bing image url link
                    resolve(bingImageUrl);
                });
            });
        } // loop through array and add value

        return response;
    }).catch((err) => {
        console.log(err);
    })

    return Promise.all([BingSearches ,GetSearchesWithImageUrl ]).then(([BingSearches , GetSearchesWithImageUrl ]) => {
        console.log(GetSearchesWithImageUrl )
         /* my response is now [{SearchTerm: "Boxing", id: '4c142f92-ba6d-46af-8dba-cb88ebabb94a', CreateDate: '2017-08-10T13:59:20.534-04:00', Image: Promise { pending } }] */

        res.status(200).json(GetSearchesWithImageUrl )
    }).catch((err) => {
        console.log(err);
    })
}

我希望Promise.All会等待我所有的承诺完成,但我似乎不明白它是如何工作的。我对任何错误的建议/解释持开放态度。

谢谢!

1 个答案:

答案 0 :(得分:1)

这是我对这个问题的最好的尝试:

// Promisified search, resolves to response array
function getBingSearchesPromise() {
    return new Promise((resolve, reject) => {
        GetBingSearches().toArray((err, response) => {
            if (err) {
                reject(err);
            } else {
                resolve(response);
            }
        });          
    });
}

// get first image url for a search term, resolves to an image URL
function getBingImagePromise(term) {
    return new Promise((resolve, reject) => {
        Bing.images(term, {count: 1}, (err, res, body) => {
            if (err) {
                reject(err);
            } else {
                resolve(body.value[0].contentUrl);
            }
        });
    });
}


// no need to pass req or res into here
// returns promise, resolves to array of images URLs
function GetSearches() {
    return getBingSearchesPromise().then(searchResponses => {
        // get all images
        let promises = searchResponses.map(searchItem => {
            return getBingImagePromise(searchItem.SearchTerm);
        });
        return Promise.all(promises);
    })    
}

// then inside your request handler where you have req and res, you can do this
GetSearches().then(images => {
    res.json(images);
}).catch(err => {
    console.log(err);
    res.status(500).end();
});

因为你的代码相当遥远,并且没有包含你想要做的文字描述,所以这是一个有关你正在努力完成的有根据的猜测。如果我的猜测错误,你可以从中学习并将其应用到你的实际问题中,或者我可以删除我的答案。

变更摘要:

  1. 单独宣传异步操作,然后使用promises构建所有逻辑(没有普通的回调)。如果我们能够看到GetBingSearches()的代码可能会传递一些参数而不是硬连接来执行特定类型的搜索,那么这可能会做得更好。

  2. 获取搜索承诺,并使用.then()等待,以获得一系列结果。

  3. .then()处理程序中,使用.map()获取每个图片网址并创建一系列承诺。

  4. 等待Promise.all()的承诺数组。

  5. 从此代码中分离reqres因为只有最终响应需要使用res所以这样您的代码可以更有用,您可以调用此代码来自响应处理程序的代码并获取结果,而不将res传递给它。

  6. 为所有错误添加错误处理。将所有错误传播回链条。

  7. 永远不要使用for/in来迭代数组(它迭代对象的属性,而不仅仅是数组元素)。如果您想要的结果是1对1阵列,那么.map()就是完美的。否则,在ES6中,使用for/of迭代数组。