return срабатывает раньше img.onload? [дубликат]

253
22 апреля 2018, 22:40

На данный вопрос уже ответили:

  • Как вернуть значение из события или из функции обратного вызова? Или хотя бы дождаться их окончания 3 ответа

Мне нужно перевести черно-белое изображения в вектор, состоящий из 1 и 0 Написал функцию, которая принимает на вход путь к файлу и возвращает массив из 1 и 0.

function readImg(file) {
    ctx.clearRect(0, 0, draw.width, draw.height);
    var img = new Image(),
        convert = [];
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
        var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data;
        for (var i = 0; i < img.width * img.height; i++) {
            if (imgdata[i*4] > 0)
                convert.push(0);
            else
                convert.push(1);
        }
    }
    img.src = file;
    return convert;
}

Но вот проблема, если я пытаюсь дальше работать с этим массивом, то его как бы не существует. К примеру:

var temp = readImg("img.png");
console.log(temp.length) //Выведет "0"

Получается, что массив convert возвращается пустым и не успевает заполнится, т.к. функция img.onload еще не выполнилась.

UPD: Прочитал про Promise, попытался прикрутить его к моему коду

function readImg(file) {
    return new Promise(function(resolve, reject) {
        ctx.clearRect(0, 0, draw.width, draw.height);
        var img = new Image(),
            convert = [];
        img.onload = function() {
            ctx.drawImage(img, 0, 0);
            var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data;
            for (var i = 0; i < img.width * img.height; i++) {
                if (imgdata[i*4] > 0)
                    convert.push(0);
                else
                    convert.push(1);
            }
            resolve(convert);
        }
        img.src = file;
    });
}

Теперь использую эту функцию так

readImg("img.png").then(function (result) {
    console.log(result);
});

Результат выводит правильный, но как мне этот result присвоить другой переменной и использовать дальше? Я хочу использовать это так:

data = [];
for (var i = 0; i < 3; i++) {
    data[i] = [];
    readImg(i + 1 + ".png").then(function (result) {
        data[i][0] = result; //ошибка Uncaught (in promise) TypeError: Cannot set property '0' of undefined
    });
}
Answer 1

Проблема. Когда функция выполняется внутри Promise значение внешней переменной i будет другим и его напрямую использовать нельзя. Я передал его как параметр.

Только у меня здесь одна и та же картинка для примера.

var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d"); 
var draw = new Object(); 
draw.width = ctx.canvas.clientWidth; 
draw.height = ctx.canvas.clientHeight; 
 
function readImg(file,num) { 
    return new Promise(function(resolve, reject) { 
        ctx.clearRect(0, 0, draw.width, draw.height); 
        var img = new Image(), 
            convert = []; 
        var myresult = new Object(); 
        myresult.num=num; 
        img.crossOrigin = "Anonymous"; 
        img.onload = function() { 
            ctx.drawImage(img, 0, 0); 
            var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data; 
            for (var i = 0; i < img.width * img.height; i++) { 
                if (imgdata[i*4] > 0) 
                    convert.push(0); 
                else 
                    convert.push(1); 
            } 
            myresult.convert=convert; 
            resolve(myresult); 
        } 
        img.src = file; 
    }); 
} 
 
data = []; 
for (var i = 0; i < 3; i++) { 
    readImg("https://i.imgur.com/K38QcUh.png",i).then(function (myresult) { 
        local_i=myresult.num; 
        data[local_i] = []; 
        data[local_i].push(myresult.convert); 
        // или data[local_i]=myresult.convert; 
        alert(data[local_i]); 
    }); 
}
<canvas id="canvas" width="5" height="5" class="playable-canvas"></canvas>

Answer 2

Ну тогда проще сделать так. Вызываем загрузку изображений одной функцией передавая ей список файлов для загрузки. После загрузки первого изображения вызывается загрузка второго и тд. После последнего запускается функция nextcode туда и пишите остальной код.

var canvas = document.getElementById("canvas"); 
var ctx = canvas.getContext("2d"); 
var data = []; 
var draw = new Object(); 
draw.width = ctx.canvas.clientWidth; 
draw.height = ctx.canvas.clientHeight; 
 
function readImgList(imglist) { 
        ctx.clearRect(0, 0, draw.width, draw.height); 
        var img = new Image(); 
        img.crossOrigin = "Anonymous"; //это нужно только для примера тк изображение загружается с другого домена 
        var k=0; 
        img.onload = function() { 
        ctx.drawImage(img, 0, 0); 
        var imgdata = ctx.getImageData(0, 0, draw.width, draw.height).data; 
        data[k]=[]; 
        for (var i = 0; i < img.width * img.height; i++) { 
            if (imgdata[i*4] > 0) 
              data[k].push(0); 
            else 
              data[k].push(1); 
            } 
            if (k+1<imglist.length) { 
              k=k+1; 
              img.src=imglist[k]; 
            } else { 
              nextcode(); 
            } 
        } 
        img.src = imglist[0]; 
} 
 
var imglist = []; 
imglist[0] = "https://i.imgur.com/K38QcUh.png"; 
imglist[1] = "https://i.imgur.com/K38QcUh.png"; 
imglist[2] = "https://i.imgur.com/K38QcUh.png"; 
readImgList(imglist); 
 
function nextcode() { 
  console.log(data); 
  //и сюда пишете весь ваш остальной код 
}
<canvas id="canvas" width="5" height="5" class="playable-canvas"></canvas>

READ ALSO
Сервер node.js отправка post запроса

Сервер node.js отправка post запроса

ЗдравствуйтеЯ написал локальный сервер node

260
Интересная задача js [дубликат]

Интересная задача js [дубликат]

На данный вопрос уже ответили:

233
Зачем нужен веб-сервер для pixijs

Зачем нужен веб-сервер для pixijs

Начал читать документацию клик и не смог понятьЗачем же обычному js фреймворку нужен веб-сервер

189
Избавиться от циклов if

Избавиться от циклов if

Проверяю мой класс games на название игрыПроверку делаю циклом if, но игр будет около 30 и что 30 циклов if делать? Не правильно же

210