在回调完成之前发生JavaScript结果

时间:2017-03-27 14:09:04

标签: javascript google-chrome

我几天前刚刚跳过JS试图制作镀铬扩展,所以很抱歉,如果这是一个简单的问题,但我似乎无法弄明白。

我的原始功能是简单地下载图像并将存储的计数增加1并添加文件大小。但是在一个图像页面上它达到了chrome的写入限制,因此我决定计算这些值并在最后写入它们。

最初返回值发生的时间比函数执行时要晚得多(所以它什么也没有返回),所以我查找了如何修复它并让它使用回调。但是,虽然它等待回调,但代码只是继续通过回调,之后的部分在其他任何事情之前执行,这意味着最终的计数将始终为0。

    // Loop through all urls
    var approx_filesize = 0;
    for(var i = 1; i < all_urls.length; i++){
        var image_url = all_urls[i];
        _download_image(image_url, folder_name, function(item){
            approx_filesize += parseInt(item);
        });
    }

    // This happens before any _download_image functions complete
    alert('end' + approx_filesize);

    // Write to storage
    chrome.storage.sync.get({
        download_count: 0,
        download_size: 0
    }, function(items) {
        chrome.storage.sync.set({
            download_count: parseInt(items.download_count) + all_images_data.length - 1,
            download_size: parseInt(items.download_size) + approx_filesize
        }, function() {
        });
    });

我只是尝试将循环移动到自己的回调函数中并且仍然没有运气,警报在第一个函数完成之前运行。

function image_url_loop_callback(callback, folder_name, all_urls){

    var approx_filesize = 0;
    for(var i = 1; i < all_urls.length; i++){
        var image_url = all_urls[i];

        _download_image(image_url, folder_name, function(filesize){
            approx_filesize += parseInt(filesize);
        });
    }
    callback(approx_filesize);
}

image_url_loop_callback(function(approx_filesize){
    alert(approx_filesize);
}, folder_name, all_urls);

如何在完成任何其他操作之前完成循环?

编辑:让它与诺言合作,这是经过调整的代码:

new Promise( function(resolve, reject) {
    var count = 1;
    var num_items = all_urls.length;
    var approx_filesize = 0;
    for(var i = 1; i < num_items; i++){
        var image_url = all_urls[i];

        _download_image(image_url, folder_name, function(item){
            approx_filesize += parseInt(item);
            count ++;
            if(count == num_items){
                resolve([num_items, approx_filesize]);
            }
        });
    }
}).then( function(stuff) {
    var num_items = stuff[0];
    var approx_filesize = stuff[1];
    chrome.storage.sync.get({
        download_count: 0,
        download_size: 0
    }, function(items) {
        chrome.storage.sync.set({
            download_count: parseInt(items.download_count) + num_items,
            download_size: parseInt(items.download_size) + approx_filesize
        }, function() {
        });
    });
});

2 个答案:

答案 0 :(得分:3)

基本上,您必须处理JavaScript的异步方面。

为此,你必须使用Promise。

这是这样的:

new Promise( () => {

    // My asynchronous code

}).then( () => {

    // My code which need to wait for the promise resolution.

});

如果您只使用最新版本的浏览器,您还可以查看async / await关键字,这使得异步处理比常规承诺更容易(但仍然是承诺)。

编辑:由于这个答案需要进一步解释和正确的代码片段,我编辑它来回答评论。

这个例子可能更容易理解:

let myFoo = "Hello";

test = new Promise( (resolve) => {

    console.log(myFoo);

    myFoo = "World!";

    setTimeout(() => {

        resolve();

    }, 4000);

}).then( () => {

    console.log(myFoo);

});

这将立即打印“Hello”和“World!” 4秒后。

这就是你如何使用promises。您可以完美地编辑在promise之外的范围中定义的变量。请不要使用var,只需坚持让我们定义一个合适的范围。

答案 1 :(得分:2)

由于javascript的异步性,你必须使用promises:

https://developers.google.com/web/fundamentals/getting-started/primers/promises