0

I am new in javascript, following is my code( not specific) to explain my question

cornerstone.loadImage(imageIdpro).then(function(image) {//doSomething}

I already know that .then(function()) is asynchronous function, my question is, is there any way that I can modify this code to avoid to use .then(), and change this to synchronous? Any help appreciated.

The reason I do not want to use .then() is because I want to slide to change some value to keep update the result when I drag slide

$("#upperBound").slider({
  range: "max",
  min: minPixelValue,
  max: maxPixelValue,
  slide: function(event, ui) {
    $("#rangeUpper").html(ui.value);
    currentUpperBound = ui.value;//currentUpperBound is current slide value
    console.log("1");
    loadAndViewImagethresholding(imageId);
    console.log("4");
  },
});

and loadAndViewImagethresholding function is something like that:

function loadAndViewImagethresholding(imageId) {
  var imageIdpro = "wadouri:" + "http://localhost:8888/dicomread/temp/" + loadfileName;
  cornerstone.loadImage(imageIdpro).then(function(image) {
    console.log("2");
    upper = currentUpperBound;//upperBound slide current value
    lower = currentLowerBound;//there is another lowerBound slide current value
    for (var i = 0; i < image.getPixelData().length; i++) {
      if (image.getPixelData()[i] < lower || image.getPixelData()[i] > upper) {
        image.getPixelData()[i] = image.minPixelValue;
      } else {
        image.getPixelData()[i] = image.maxPixelValue;//Here is the problem!!image.getPixelData()[i] is a image pixel value at [i], every time when slide current value (upper or lower value)changes, this image.getPixelData()[i] has already changed 
      }
    }
    //after that for loop, image.getPixelData(which is a data array) has already changed ( after each time slide value update)
    cornerstone.displayImage(elementthresh, image);//but this function seems has been skipped
    console.log("3");
  });
}

and because .then() is asynchronous function, this code will implement( number in console) like: 1-4-2-3 rather than 1-2-3-4 as I expect which seems skip displayImage(); (update result) So that is way I am thinking if I can change this asynchronous function to synchronous, it will implement in 'right' order, and it will keep updating when I drag the slide bar.

MMzztx
  • 243
  • 5
  • 15
  • What is issue using `.then()`? – guest271314 Jan 30 '17 at 03:10
  • 2
    `cornerstone.loadImage(imageIdpro)` returns a Promise ... ergo, it is asynchronous ... nothing can turn an asynchronous function into a synchronous one - rather than running away scared from asynchronous code, you should, if you want to use javascript at all, embrace asynchronous code and all it has to offer – Jaromanda X Jan 30 '17 at 03:10
  • 1
    Not officially as of today. The ability to [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) will likely be standardized this year ([ES 2017](https://github.com/tc39/proposals/blob/master/finished-proposals.md)). That'll allow the application to run asynchronously but have an appearance in code that's similar to synchronous. – Jonathan Lonowski Jan 30 '17 at 03:12
  • @guest271314 let me make my question to be more specific – MMzztx Jan 30 '17 at 03:13
  • Having said that, ES7 (or later I think) introduces `async/await` ... which allows a more imperative style of coding that doesn't look as frightening for some ... the above would be `var image = await cornerstone.loadImage(imageIdpro); doSomethingWith(image);` - however, this can only be perfomed inside a function tagged `async`, and returning from that function one would return a Promise ... – Jaromanda X Jan 30 '17 at 03:14
  • @JaromandaX I am gonna make my question to be more specific, let see if you can give me some advise – MMzztx Jan 30 '17 at 03:14
  • @JaromandaX I have made it more specific, any suggestion? – MMzztx Jan 30 '17 at 03:26
  • can you explain, are `currentUpperBound`, `currentLowerBound`, `upper` and `lower` global variables? Do they need to be? and where is `currentLowerBound` defined? – Jaromanda X Jan 30 '17 at 03:46
  • You can `return` `cornerstone.loadImage(imageIdpro)`, chain `.then()` to perform asynchronous functions in sequence – guest271314 Jan 30 '17 at 03:47
  • I just about posted an answer when the question was close. I don't think the duplicate is of any help to be honest – Jaromanda X Jan 30 '17 at 03:50
  • @JaromandaX re-opened – Phil Jan 30 '17 at 03:50
  • Does `cornerstone.displayImage(elementthresh, image)` return a `Promise`? – guest271314 Jan 30 '17 at 03:53
  • @JaromandaX currentUpperBound, currentLowerBound are slide current value(one 'upperBound' as in my question and there is other 'lowerBound') – MMzztx Jan 30 '17 at 04:17
  • yeah, but I can't see where they are declared – Jaromanda X Jan 30 '17 at 04:18
  • @JaromandaX I am sorry, I made some comments, and lowerBound is totally same with upperBound – MMzztx Jan 30 '17 at 04:28
  • I've posted an answer with two scenarios, they are a little more complicated than they need to be because of the apparent globals, but I believe the core of the code should serve your purpose - my guess is, the second code block is what you want to achieve - I wont edit my answer for every edit of your question, I'm sure you can take the code on offer, and make any adjustments required – Jaromanda X Jan 30 '17 at 04:33
  • @JaromandaX Thank you anyway! I am going to try your suggestion – MMzztx Jan 30 '17 at 04:40

2 Answers2

0

Keep chaining the promises. That's how they're designed to work. Note the return statement in the function to return the promise for future chaining.

$("#upperBound").slider({
    range: "max",
    min: minPixelValue,
    max: maxPixelValue,
    slide: function(event, ui) {
        $("#rangeUpper").html(ui.value);
        currentUpperBound = ui.value;
        console.log("1");
        loadAndViewImagethresholding(imageId).then(function() {
            console.log("4");
        });
    },
});

function loadAndViewImagethresholding(imageId) {
    var imageIdpro = "wadouri:" + "http://localhost:8888/dicomread/temp/" + loadfileName;
    return cornerstone.loadImage(imageIdpro).then(function(image) {
        console.log("2");
        upper = currentUpperBound;
        lower = currentLowerBound;
        for (var i = 0; i < image.getPixelData().length; i++) {
            if (image.getPixelData()[i] < lower || image.getPixelData()[i] > upper) {
                image.getPixelData()[i] = image.minPixelValue;
            } else {
                image.getPixelData()[i] = image.maxPixelValue;
            }
        }
        cornerstone.displayImage(elementthresh, image);
        console.log("3");
    });
}
Andy Ray
  • 30,372
  • 14
  • 101
  • 138
  • The point is, It looks like upperBound completes fast than 'loadAndViewImagethresholding()' which cause 'cornerstone.displayImage(elementthresh, image);' does not (do not have time to)implement. From performance it looks like that, but still thank you, I learnt a new thing! – MMzztx Jan 30 '17 at 04:32
0

In the answers below, as I am not sure why currentUpperBound, currentLowerBound, upper and lower seem to be globals in your code, I've tried to write code that "respects" that fact

This code will make sure that each loadImage completes before the next one is started, by chaining the promises, using var p

var p = Promise.resolve();
var loading = [];

$("#upperBound").slider({
    range: "max",
    min: minPixelValue,
    max: maxPixelValue,
    slide: function(event, ui) {
        $("#rangeUpper").html(ui.value);
        var upperBound = currentUpperBound = ui.value;
        var lowerBound = currentLowerBound;
        p = p.then(function() {
            loadAndViewImagethresholding(imageId, upperBound, lowerBound);
        }
    },
});

function loadAndViewImagethresholding(imageId, upperBound, lowerBound) {
    var imageIdpro = "wadouri:" + "http://localhost:8888/dicomread/temp/" + loadfileName;
    return cornerstone.loadImage(imageIdpro).then(function(image) {
        for (var i = 0; i < image.getPixelData().length; i++) {
            lower = lowerBound;
            upper = upperBound;
            if (image.getPixelData()[i] < lower || image.getPixelData()[i] > upper) {
                image.getPixelData()[i] = image.minPixelValue;
            } else {
                image.getPixelData()[i] = image.maxPixelValue;
            }
        }
        cornerstone.displayImage(elementthresh, image);
    });
}

However, I suspect that you want to "cancel" any loadImage in progress if the slider moves before the image is loaded. While you can't cancel the loadImage function, you can prevent the subsequent .then form executing - it's a bit fiddly, but I can't think of a better way off the top of my head

var loading = [];

$("#upperBound").slider({
    range: "max",
    min: minPixelValue,
    max: maxPixelValue,
    slide: function(event, ui) {
        // stops any .then's yet to be fired
        loading.forEach(function(x) {
            x.ok = false;
        });
        loading = [];
        $("#rangeUpper").html(ui.value);
        currentUpperBound = ui.value;
        loadAndViewImagethresholding(imageId, currentUpperBound, currentLowerBound);
    },
});

function loadAndViewImagethresholding(imageId, upperBound, lowerBound) {
    var imageIdpro = "wadouri:" + "http://localhost:8888/dicomread/temp/" + loadfileName;
    var x = { ok: true; }
    cornerstone.loadImage(imageIdpro).then(function(image) {
        if (x.ok) {
            lower = lowerBound;
            upper = upperBound;
            for (var i = 0; i < image.getPixelData().length; i++) {
                if (image.getPixelData()[i] < lower || image.getPixelData()[i] > upper) {
                    image.getPixelData()[i] = image.minPixelValue;
                } else {
                    image.getPixelData()[i] = image.maxPixelValue;
                }
            }
            cornerstone.displayImage(elementthresh, image);
        }
    });
    loading.push(x);
}
Jaromanda X
  • 53,868
  • 5
  • 73
  • 87