麻烦for循环和promise,因为我需要遍历object来获取值

时间:2016-12-13 07:31:02

标签: javascript jquery asynchronous firebase firebase-realtime-database

我有一个名为previewMessages的数组,我需要遍历一个对象messages,并获得一堆值。其中一个值需要异步调用,当然如果我想在for循环后使用previewMessages变量,这将无法工作,例如对它进行排序。

以下是代码:

var displayMessages = function(messages) {
    let previewMessages = [];
    for (let messageID in messages) {
        let message = messages[messageID];
        let messageObj = {};

        Promise.resolve(getItemsById([message.context.itemID])).then(function(itemInfo) {
            messageObj.title = itemInfo[Object.keys(itemInfo)[0]].title;
        });

        previewMessages.push(messageObj);
    }
}

我无法promise.all,因为需要迭代消息,我需要异步调用来获取标题。

如果这有帮助,这是第一个调用上述函数的函数:

var getUserMessages = function(id) {
    usersRef.child(`${id}/chats/`).on('value', function(snapshot) {
        displayMessages(snapshot.val());
    })
}

1 个答案:

答案 0 :(得分:2)

两种替代方案:

如果异步调用可以并行运行(即使可能有100个,也没关系),你可以使用Promise.all

let previewMessages = [];
let promises = [];

// Build the array of promises
for (let messageID in messages) {
    let message = messages[messageID];
    let messageObj = {};
    previewMessages.push(messageObj);

    messageObj.timeStamp = message.context.latestPost;
    messageObj.user = message.context.otherUsername;
    messageObj.picture = message.context.itemImageURL;
    promises.push(getItemsById([message.context.itemID]).then(itemInfo => {
        messageObj.title = itemInfo[Object.keys(itemInfo)[0]].title;
    }));
}
// Wait for them all to complete
Promise.all(promises).then(() => {
    // use previewMessages
});

如果他们顺序,请在执行下一步之前等待每一个:

let previewMessages = [];
let promise = Promise.resolve();

// Loop through building up the `then` chain
for (let messageID in messages) {
    let message = messages[messageID];
    let messageObj = {};
    previewMessages.push(messageObj);

    // This one will wait for the next
    promise = promise.then(() => {
        messageObj.timeStamp = message.context.latestPost;
        messageObj.user = message.context.otherUsername;
        messageObj.picture = message.context.itemImageURL;
        return getItemsById([message.context.itemID]).then(itemInfo => {
            messageObj.title = itemInfo[Object.keys(itemInfo)[0]].title;
        });
    });
}
// Wait for the last one to complete
promise.then(() => {
    // Use previewMessages
});

但我可能会利用文字来填写我们不必等待的值:

异步:

let previewMessages = [];
let promises = [];

// Build the array of promises
for (let messageID in messages) {
    let message = messages[messageID];
    let messageObj = {
        timeStamp: message.context.latestPost,
        user: message.context.otherUsername,
        picture: message.context.itemImageURL
    };
    previewMessages.push(messageObj);

    promises.push(getItemsById([message.context.itemID]).then(itemInfo => {
        messageObj.title = itemInfo[Object.keys(itemInfo)[0]].title;
    }));
}
// Wait for them all to complete
Promise.all(promises).then(() => {
    // use previewMessages
});

同步:

let previewMessages = [];
let promise = Promise.resolve();

// Loop through building up the `then` chain
for (let messageID in messages) {
    let message = messages[messageID];
    let messageObj = {
        timeStamp: message.context.latestPost,
        user: message.context.otherUsername,
        picture: message.context.itemImageURL
    };
    previewMessages.push(messageObj);
    // This one will wait for the next
    promise = promise.then(() => {
        return getItemsById([message.context.itemID]).then(itemInfo => {
            messageObj.title = itemInfo[Object.keys(itemInfo)[0]].title;
        });
    });
}
// Wait for the last one to complete
promise.then(() => {
    // Use previewMessages
});

也许一对简化的,可运行的例子会有所帮助。另外,你已经提到“......问题是func2从func1获取返回对象......”所以让我们将它添加到混合中。

并行:

const messages = {
    "one": {name: "Message one"},
    "two": {name: "Message two"},
    "three": {name: "Message three"},
    "four": {name: "Message four"}
};

let previewMessages = [];
let promises = [];

// Build the array of promises
for (let messageID in messages) {
    let message = messages[messageID];
    let messageObj = {
        name: message.name
    };
    previewMessages.push(messageObj);

    promises.push(func1(message).then(func2).then(info => {
        messageObj.info = info;
    }));
}
// Wait for them all to complete
Promise.all(promises).then(() => {
    // use previewMessages
    console.log("Done! Result:", previewMessages);
});

function func1(message) {
    return new Promise(resolve => {
        // Use setTimeout for async
        setTimeout(() => {
            console.log("func1 resolving on " + message.name);
            resolve(message.name + " - func1");
        }, Math.random() * 500);
    });
}
function func2(info) {
    return new Promise(resolve => {
        // Use setTimeout for async
        setTimeout(() => {
            console.log("func2 resolving on " + info);
            resolve(info +  " - func2");
        }, Math.random() * 500);
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}

序列:

const messages = {
    "one": {name: "Message one"},
    "two": {name: "Message two"},
    "three": {name: "Message three"},
    "four": {name: "Message four"}
};

let previewMessages = [];
let promise = Promise.resolve();

// Build the promise chain
for (let messageID in messages) {
    let message = messages[messageID];
    let messageObj = {
        name: message.name
    };
    previewMessages.push(messageObj);

    promise = promise.then(() => func1(message).then(func2).then(info => {
        messageObj.info = info;
    }));
}
// Wait for the last one to finish
promise.then(() => {
    // use previewMessages
    console.log("Done! Result:", previewMessages);
});

function func1(message) {
    return new Promise(resolve => {
        // Use setTimeout for async
        setTimeout(() => {
            console.log("func1 resolving on " + message.name);
            resolve(message.name + " - func1");
        }, Math.random() * 500);
    });
}
function func2(info) {
    return new Promise(resolve => {
        // Use setTimeout for async
        setTimeout(() => {
            console.log("func2 resolving on " + info);
            resolve(info +  " - func2");
        }, Math.random() * 500);
    });
}
.as-console-wrapper {
  max-height: 100% !important;
}