У меня проблема, когда в обратном вызове постоянно меняется порядок индекса цикла. В приведенном ниже коде показано, что я пробовал, цель, которую я пытаюсь достичь, - добавить маркеры на основе доступных слоев. Однако порядок, в котором я перебираю слои, должен быть таким же, в каком я добавляю маркеры. Позже, когда я исправлю эту проблему, цель состоит в том, чтобы пользователи могли щелкнуть созданный маркер, что приведет к открытию слоя с информацией. Кто-нибудь знает, какое решение? Я экспериментировал с комментариями @patrickRoberts и @stian.

$(function(){

//  I've tried the following:
//  – async/await with promises
//  – JavaScript Closures
//  – Closures with IIFE (see example below)

'use strict';

//Cache DOM
let $win                = $(window),
    $doc                = $(document),
    $body               = $('body'),
    $layer              = $('.layer'),
    $drawingImage       = $('.drawings__image'),
    $markerContainer    = $('.markers');

//Init
_addMarkers();

function _addMarkers(){
    for(var i = 0; i < $layer.length; i++){
        //Right order
        console.log(i);

        (function(i){
            _calculateScaleFactor($drawingImage.eq(0), function(data){

                //Wrong order
                console.log(i);
            });
        })(i);
    }
}

function _createMarker(x, y, ){
    return $(`<span class="markers__single-marker" style="left:${x}px; top:${y}px;">${i}</span>`);
}

function _calculateScaleFactor(image, callback){
    let newImage    = new Image();

    newImage.src = image.attr('src');
    newImage.onload = function(){
        let scaleFactor = newImage.width / image.width();
        callback(scaleFactor);
    }
}

})

-1
Rick van den Broek 14 Мар 2018 в 13:30

2 ответа

Лучший ответ

После нескольких часов экспериментов (вообще без ожидания / асинхронности) я наконец исправил это с помощью async и await. Особая благодарность @stian! Надеюсь, что решение также поможет другим, см. Код ниже:

$(function(){

'use strict';

//Cache DOM
let $win                = $(window),
    $doc                = $(document),
    $body               = $('body'),
    $layer              = $('.layer'),
    $drawingImage       = $('.drawings__image'),
    $markerContainer    = $('.markers');

//Init
_addMarkers();

async function _addMarkers(){
    for(var i = 0; i < $layer.length; i++){
        let _self = $layer.eq(i),
            layerData = {
                x: _self.data('x'),
                y: _self.data('y')
            }
        await _calculateScaleFactor($drawingImage.eq(0)).then(function(resolve){
            layerData.x = (layerData.x / resolve) + $drawingImage.eq(0).offset().left;
            layerData.y = (layerData.y / resolve) + $drawingImage.eq(0).offset().top;

            $markerContainer.append( _createMarker(layerData.x, layerData.y, i) );
            console.log(i);
        });
    }
}

function _createMarker(x, y, i){
    return $(`<span class="markers__single-marker" style="left:${x}px; top:${y}px;">${i}</span>`);
}

function _calculateScaleFactor(image){
    return new Promise(function(resolve, reject){
        let newImage    = new Image();

        newImage.src = image.attr('src');
        newImage.onload = function(){
            let scaleFactor = newImage.width / image.width();
            resolve(scaleFactor);
        }
    });
}

})

0
Rick van den Broek 19 Мар 2018 в 22:21

Вот способ сделать это с помощью async / await и promises. Надеюсь, это будет полезно.

$(() => {
  //your array of elements
  let arr = ["hello", "hi", "bye"]
  calculate(arr)

})

async function calculate(arr){

  for(let i = 0; i < arr.length; i++){

    console.log(i, arr[i])
    let result = await someAsyncStuff(arr[i])
    console.log(i, result)
  }

}

function someAsyncStuff(el){
  return new Promise((resolve, reject) => {
    //your async code here
    setTimeout(resolve, 2000, el)
  })
}
-1
stian 16 Мар 2018 в 14:23