【问题标题】:JavaScript result happening before callbacks completeJavaScript 结果在回调完成之前发生
【发布时间】:2017-03-27 14:09:04
【问题描述】:

我对 JS 完全陌生,几天前开始尝试做一个 chrome 扩展,如果这是一个简单的问题,很抱歉,但我似乎无法弄清楚。

我最初的功能是简单地下载图像并将存储的计数增加 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);

如何让循环在其他任何事情完成之前完成?

编辑:可以使用 promise,这是调整后的代码:

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() {
        });
    });
});

【问题讨论】:

    标签: javascript google-chrome


    【解决方案1】:

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

    为此,您必须使用 Promise。

    这样工作:

    new Promise( () => {
    
        // My asynchronous code
    
    }).then( () => {
    
        // My code which need to wait for the promise resolution.
    
    });
    

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

    编辑:由于此答案需要进一步解释和正确的代码 sn-ps,我对其进行了编辑以回答评论。

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

    let myFoo = "Hello";
    
    test = new Promise( (resolve) => {
    
        console.log(myFoo);
    
        myFoo = "World!";
    
        setTimeout(() => {
    
            resolve();
    
        }, 4000);
    
    }).then( () => {
    
        console.log(myFoo);
    
    });
    

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

    这就是你使用 Promise 的方式。您可以完美地编辑在 Promise 之外的范围内定义的变量。请不要使用 var,只要坚持 let 并定义一个合适的范围即可。

    【讨论】:

    • 谢谢,正要和其他人澄清如何使用它,现在就试试吧:)
    • 小问题 - 我需要来自promise 的变量进入then 部分,看起来你使用resolve,但在其余部分完成之前执行哈哈。如何让变量结束?
    • 我编辑了我的答案给你一个合适的例子,因为我不确定你遇到了什么问题。
    • 谢谢,它运行循环和执行解析的速度太快了,尽管我设法通过增加每次函数完成的计数来修复它。希望这样,即使需要很长时间,它仍然可以工作:)
    【解决方案2】:

    由于 javascript 的异步特性,您必须使用 Promise:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-20
      • 1970-01-01
      • 2021-01-03
      • 2020-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多