【问题标题】:Promise.All - Promise Within Promise Not Being ResolvedPromise.All - Promise 中的 Promise 未解决
【发布时间】:2018-02-06 08:56:53
【问题描述】:

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

我正在连接到一个数据源并将我的第一个承诺解析为一个数组。之后,我想获取这些结果,并通过另一个 Promise 循环遍历结果,并向使用外部 API 调用的数组添加另一个值。

经过研究,听起来我需要使用 Promise.All 以便在返回我的响应之前完成承诺,但我仍然处于待处理状态,即我添加到数组中的值而不是预期值.同样,我只是在学习节点和承诺,所以我的方法可能完全有缺陷,在这种情况下,我愿意接受任何关于更好地完成我想要完成的工作的建议。

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 会等待我的所有承诺完成,但我似乎不明白它是如何工作的。我愿意接受任何关于我做错了什么的建议/解释。

谢谢!

【问题讨论】:

  • 你打电话给 return Promise.all([Searches,Images]),但我没有看到任何地方定义了 SearchesImages。它们是什么?
  • Promise.all([Searches,Images]) 中似乎搜索和图像是未定义的,不是吗?
  • 应该是Promise.all([BingSearches, GetSearchesWithImageUrl])
  • 这段代码看起来很遥远。请“用文字”描述您想要实现的目标(无需我们猜测),以便我们建议修复版本。
  • 另外,由于操作应该在最低级别进行承诺,我们可能需要知道 GetBingSearches() 正在做什么才能提供最佳答案。

标签: javascript promise


【解决方案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. 分别承诺异步操作,然后使用承诺构建所有逻辑(无普通回调)。如果我们可以看到 GetBingSearches() 的代码,这可能会做得更好,它可能应该有一些参数传递给它,而不是硬连线来执行特定类型的搜索。

  2. 获取搜索承诺并使用.then() 等待它以获取结果数组。

  3. .then() 处理程序中,使用 .map() 获取每个图像 URL 并创建一个承诺数组。

  4. 等待Promise.all() 的一系列承诺。

  5. 从这段代码中分离出reqres,因为只有最终的响应需要使用res,所以这样你的代码可以更有用,你可以从响应处理程序中调用这段代码,然后无需将res 传递给它即可获得结果。

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

  7. 切勿使用for/in 来迭代数组(它会迭代对象的属性,而不仅仅是数组元素)。如果您想要的结果是一对一的数组,那么.map() 非常适合。否则,在 ES6 中,使用 for/of 来迭代数组。

【讨论】:

  • 这太棒了。我很欣赏总结和试图让我指向正确方向的尝试。这更简洁,真的帮助我理解了 Promise 的流程以及它们是如何链接在一起的。我认为我现在唯一需要弄清楚的是 .map 是如何工作的,只需将图像添加到我的数组中即可。类似searchResponses.map(searchItem => { searchItem.bingImageUrl = getBingImagePromise(searchItem.SearchTerm); return searchItem });
  • 我想通了...我在 Promise.All 上使用 .then 将响应添加到我的数组中。再次感谢您的解释。这真的很有帮助。
猜你喜欢
  • 2020-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-21
  • 2017-10-24
  • 2017-09-10
相关资源
最近更新 更多