等待的 Promise 仍然返回 <pending>

Posted

技术标签:

【中文标题】等待的 Promise 仍然返回 <pending>【英文标题】:awaited Promises still returning <pending> 【发布时间】:2019-12-08 08:39:16 【问题描述】:

我有一组关于人的数据对象。每个人员对象都包含 0-n 个 URL,用于附加信息(人员的客人)。

我想处理这个列表,调用每个“来宾”URL,并在原始数据集中包含来宾的姓名。

上下文:这是一个 AWS lambda 函数。我正在使用lambda-local 在本地运行它。 (lambda-local -l index.js -e fixtures/test_event1.json)。

我已成功使用 await/async 检索初始数据集。

但我无法获得这些关于客人信息的进一步电话。它总是显示一个待处理的 Promise,即使等待结果。

// index.js

const fetch = require('node-fetch');

exports.handler = async function(event)

    try 
        let registrations = await getEventRegistrations();
        console.log(registrations);

/* All good here - sample console output
[  contactId: 43452967,
    displayName: 'aaa, bbb',
    numGuests: 0,
    guestUrls: [] ,
   contactId: 43766365,
    displayName: 'bbb, ccc',
    numGuests: 1,
    guestUrls:
     [ 'https://<URL>' ] ,
   contactId: 43766359,
    displayName: 'ccc, ddd',
    numGuests: 2,
    guestUrls:
     [ 'https://<URL>',
       'https://<URL> ]  ]
*/

        // Expanding the guest URLs is proving problematic - see expandGuests function below
        registrations = registrations.map(expandGuests);
        console.log(registrations);


/* Registrations are just pending Promises here, not the real data

[ Promise  <pending> ,
  Promise  <pending> ,
  Promise  <pending>  ]

*/

        return 
            statusCode: 200,
            headers: 
                'Access-Control-Allow-Origin': '*',
            ,
            body: JSON.stringify(registrations),
        ;
    
    catch (exception) 
        console.log(exception);
        return 
            statusCode: 500,
            body: 'Unable to retrieve data.'
        ;
    
;

function getEventRegistrations() 
    return fetch('<URL>')
    .then(res => res.json())
    .catch(function (error) 
        console.log('Event registrants request failed', error);
        return null;
    );


function getGuestName(url) 
    return fetch(url)
    .then(res => res.json())
    .then(guest => guest.DisplayName)
    .catch(function (error) 
        console.log('Guest name request failed', error);
        return null;
    );


async function expandGuests(data) 

    const promises = data.guestUrls.map(url => getGuestName(url));
    data.guestNames = await Promise.all(promises);

    return data;



如何解决这些待处理的 Promise 并返回有用的数据?

谢谢。

【问题讨论】:

你不能。承诺是一种传染性。如果一个函数使用它们,那么每个使用该函数的函数都必须使用它们。这就是异步代码的工作原理。 每个async 函数都会返回一个承诺。他们就是这样工作的。因此,您必须在您的 async 函数调用中使用 .then()await 才能获得其最终解析值。 【参考方案1】:

cmets 指出映射 async 函数将返回 Promise 数组是正确的。他们没有明确提到的是你有两张地图,哪一张有问题。

问题出在一行:

reservations = reservations.map(expandGuests);

任何时候你使用 map,你都需要真正解决返回的承诺。

所以:

const mappedPromises = reservations.map(expandGuests);  //returns an Array of Pending promises
const mappedReservations = await Promise.all(mappedPromises);  //resolves the promises

【讨论】:

是的!谢谢你。这解决了它。很明显,另一个答案现在是准确的,但只有这种洞察力最终在正确的地方发光。【参考方案2】:

array.map 不包含任何等待承诺的逻辑。它只是为数组的每个元素调用函数,然后同步生成一个结果数组。如果您传入异步函数,则结果是一组承诺(因为所有异步函数都返回承诺)。

您需要使用Promise.all 创建一个承诺,该承诺将在所有单独的承诺都解决后解决,然后await 那。

const promises = data.guestUrls.map(url => getGuestName(url));
data.guestNames = await Promise.all(promises);

P.S,我强烈建议不要将 async/await 与 .then 混合使用。您真正需要这样做的情况非常少见,因此大多数时候您只是让代码更难理解。比如这个函数:

async function getGuestName(url) 
    return await fetch(url)
    .then(res => res.json())
    .then(guest => guest.DisplayName)
    .catch(function (error) 
        console.log('Guest name request failed', error);
        return null;
    );

应该这样做:

async function getGuestName(url) 
  try 
    const res = await fetch(url);
    const guest = await res.json();
    return guest.DisplayName;
   catch (error) 
    console.log('Guest name request failed', error);
    return null;
  

或者像这样

 function getGuestName(url) 
    return fetch(url)
    .then(res => res.json())
    .then(guest => guest.DisplayName)
    .catch(function (error) 
        console.log('Guest name request failed', error);
        return null;
    );



【讨论】:

感谢您的快速回复。将expandGuests 函数更改为:` async function expandGuests(data) const promises = data.guestUrls.map(url => getGuestName(url)); data.guestNames = 等待 Promise.all(promises);返回数据; ` 导致输出 ` [ Promise , Promise , Promise ] ` (来自console.log(registrations)registrations = registrations.map(expandGuests); 之后的调用) 再次感谢@nicholas-tower。额外的“ps”点也非常有用,现在已实施。

以上是关于等待的 Promise 仍然返回 <pending>的主要内容,如果未能解决你的问题,请参考以下文章

useState 与异步函数返回 Promise <pending>

为啥我的函数返回 Promise <pending> [重复]

Promise.all() 返回未定义的 Promise <Pending> 数组,尽管类似的解决方案返回成功的替代方案

为啥我的异步函数返回 Promise <pending> 而不是一个值?

异步函数返回 Promise <Pending>

Node-fetch 返回 Promise <pending> 而不是所需的数据 [重复]