如何使用回调创建异步循环?

时间:2018-03-14 10:30:24

标签: javascript jquery loops callback closures

我遇到一个问题,即循环的de index顺序在回调中不断变化。请参阅下面的代码,了解我尝试过的内容,我要实现的目标是根据可用图层添加标记。但是,我在图层上循环的顺序必须与添加标记的顺序相同。稍后,当我解决此问题时,目标是用户可以单击生成的标记,这将导致打开信息的图层。有谁知道解决方案是什么?我已经尝试了@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);
    }
}

})

2 个答案:

答案 0 :(得分:0)

经过几个小时的实验(根本没有等待/异步经验)我终于用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);
        }
    });
}

})

答案 1 :(得分:-1)

使用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)
  })
}