未知数量的承诺是否取决于先前的承诺结果?

时间:2018-11-06 18:10:40

标签: javascript promise

我正在尝试编写一个从API检索用户所有数据的函数。不幸的是,该API每个请求仅返回50条数据。为了检索结果的下一个“页面”,需要发出另一个GET请求,并带有一个额外的路径来指示结果页面。

(在我的情况下,API是Imgur,数据段是用户的相册。)

我正在用Promises做到这一点。函数populateAlbumList成功返回仅结果的第一页

我试图对其进行修改,以在函数populateAlbumList2中获得更多页面的结果,但是它无法正常工作。

如何使这些有条件嵌套的诺言起作用? (我不想使用像bluebird / q这样的库,因为我想了解概念和模式本身。)

/**
 * Performs an AJAX get request to the Imgur API, retrieving all the albums owned by the user. When the albums are
 * populated, they are logged to the extension settings page's console.
 * @returns {Promise<void>}
 */
async function populateAlbumList() {
    const username = await getItemFromStorage(STORAGE_USERNAME, ERROR_STORAGE_USERNAME_NOT_FOUND);
    const ALBUMS_URL = `https://api.imgur.com/3/account/${username}/albums`;

    // Fetch the albums for the currently logged in user
    return fetch(ALBUMS_URL, {
        method: "GET",
        headers: {
            "Authorization": "Bearer " + CLIENT_ID,
            "Content-type": "application/json; charset=UTF-8"
        }
    })
        .then(response => response.json())
        .then(json => json.data)
        .then(albums => albums.forEach(album => addAlbumToPage(album)));
}

/**
 * Performs an AJAX get request to the Imgur API, retrieving all the albums owned by the user. When the albums are
 * populated, they are logged to the extension settings page's console.
 * @returns {Promise<Array>}
 */
async function populateAlbumList2() {
    const username = await getItemFromStorage(STORAGE_USERNAME, ERROR_STORAGE_USERNAME_NOT_FOUND);
    let ALBUMS_URL = `https://api.imgur.com/3/account/${username}/albums`;
    const allAlbums = [];
    let page = 0;
    const promises = [];

    await getAlbumsFromImgur()
        .then(() => console.log(allAlbums));

    function getAlbumsFromImgur() {
        if (page > 0) {
            ALBUMS_URL = `https://api.imgur.com/3/account/${username}/albums` + page;
        }

        promises.push(
            fetch(ALBUMS_URL, {
            method: "GET",
            headers: {
                "Authorization": "Bearer " + CLIENT_ID,
                "Content-type": "application/json; charset=UTF-8"
            }
        })
            .then(response => response.json())
            .then(json => json.data)
            .then(albums => {
                allAlbums.push(albums);

                if (albums.length >= 50) {
                    page++;
                    promises.push(getAlbumsFromImgur());
                }
            })
        );
    }
}

1 个答案:

答案 0 :(得分:1)

由于您正在使用async函数,因此您无需直接处理承诺,只需使用await并编写逻辑流程即可。首先,让我们将其应用于仅获得第一页,以便我们可以看到它如何简化了功能;查看***注释:

async function populateAlbumList() {
    const username = await getItemFromStorage(STORAGE_USERNAME, ERROR_STORAGE_USERNAME_NOT_FOUND);
    const ALBUMS_URL = `https://api.imgur.com/3/account/${username}/albums`;

    // Fetch the albums for the currently logged in user
    // *** Use await to consume the promise
    const response = await fetch(ALBUMS_URL, {
        method: "GET",
        headers: {
            "Authorization": "Bearer " + CLIENT_ID,
            "Content-type": "application/json; charset=UTF-8"
        }
    });
    // Note: You have to check for errors
    if (!response.ok) {
        throw new Error("HTTP error " + response.status);
    }
    // Read and parse the JSON, get the `data` property from it using destructuring
    // *** Use await to consume the promise
    let { data: albums } = await response.json();
    // Add the albums; no need for `forEach` when we have `for-of` available to us
    for (const album of albums) {
        addAlbumToPage(album);
    }
}

现在让我们扩展该功能,以便它继续对后续页面进行请求,直到返回少于50个结果:

async function populateAlbumList() {
    const username = await getItemFromStorage(STORAGE_USERNAME, ERROR_STORAGE_USERNAME_NOT_FOUND);
    const ALBUMS_URL = `https://api.imgur.com/3/account/${username}/albums`;

    // Start on page 0
    let page = 0;
    let albums; // We'll need this in our while condition below
    do {
        // Fetch the albums for the currently logged in user,
        // adding in the page if page > 0
        const response = await fetch(
            page === 0 ? ALBUMS_URL : ALBUMS_URL + page, // Seems odd there's no `/` or `?page=` or similar
            {
                method: "GET",
                headers: {
                    "Authorization": "Bearer " + CLIENT_ID,
                    "Content-type": "application/json; charset=UTF-8"
                }
            }
        );
        if (!response.ok) {
            throw new Error("HTTP error " + response.status);
        }
        // Read and parse the JSON, get the `data` from it
        albums = (await response.json()).data;
        // Add the albums
        for (const album of albums) {
            addAlbumToPage(album);
        }
        ++page;

        // Keep going until we get fewer than 50 back
    } while (albums.length >= 50);
}

请注意,我还添加了一个检查以查看fetch是否有效,这是您的原始代码所缺少的。不仅仅是您,大多数人们忘记了包括那张支票(以至于我wrote it up出现在我贫乏的小博客上)。