Можете ли вы дождаться обратного вызова JavaScript? - PullRequest
22 голосов
/ 12 января 2009

Я пытаюсь использовать диалоговую библиотеку предупреждений jQuery из http://abeautifulsite.net/notebook/87 вместо предупреждений по умолчанию (которые, на мой взгляд, выглядят довольно ужасно). Кажется, это отличная библиотека, но нет примера того, как использовать библиотеку jConfirm.

Мне нужно сделать что-то вроде этого:

function confirm() {
        var result = false;
        var response = false;
        jConfirm('are you sure?', 'Confirmation Dialog',
          function(r) {
            result = r;
            response = true;
            return r;
        });
        if (response == true) {
            alert(result);
            return result;
        }
        else {
            //wait for response
            alert('hi');
        }
    }

и мой звонок с моей кнопки .net:

Я разместил комментарий на веб-сайте плагина (только сегодня утром), и Google выполнил поиск javascript и ожидает завершения обратного вызова без результатов.

Есть какие-нибудь идеи о том, как правильно использовать обратный вызов для получения результата до выполнения остальной части javascript?

Спасибо.

Ответы [ 9 ]

19 голосов
/ 13 января 2009

Вы только что установили большое ограничение в JavaScript. Как только ваш код входит в асинхронный мир, невозможно вернуться к классическому процессуальному процессу выполнения.

В вашем примере решением было бы сделать цикл, ожидающий ответа. Проблема в том, что JavaScript не предоставляет никаких инструкций, которые позволят вам выполнять циклы бесконечно, не занимая при этом 100% вычислительной мощности. Таким образом, вы в конечном итоге заблокируете браузер, иногда до такой степени, что ваш пользователь не сможет ответить на фактический вопрос.

Единственное решение здесь - придерживаться асинхронной модели и сохранять ее. Я советую вам добавить обратный вызов к любой функции, которая должна выполнять некоторую асинхронную работу, чтобы вызывающий мог выполнить что-то в конце вашей функции.

function confirm(fnCallback) 
{
    jConfirm('are you sure?', 'Confirmation Dialog', function(r) 
    {
        // Do something with r 

        fnCallback && fnCallback(r); // call the callback if provided
    });
}

// in the caller

alert('begin');

confirm(function(r)
{
    alert(r);

    alert('end');
})
16 голосов
/ 13 января 2009
jConfirm('are you sure?', 'Confirmation Dialog',
    function(r) {
        result = r;
        response = true;
        return r;
    }
);
if (response == true) {

Это выдает неверное понимание последовательности событий, происходящих с использованием асинхронного кода. Только то, что вы написали это встроенным, не означает, что он будет выполняться строго сверху вниз.

  1. jConfirm вызывается, получая функцию в качестве одного из своих параметров, которые она запоминает.
  2. jConfirm отображает свой интерфейс на странице и сразу же возвращается.
  3. Строка 'if (response == true)' выполняется. На самом деле это должно просто читать «if (response)», логическое сравнение излишне. Но в любом случае ответ, конечно, ложный. Ваша функция сдается и выходит, возвращая управление браузеру.
  4. Пользователь щелкает пользовательский интерфейс jConfirm.
  5. jConfirm только сейчас переходит в действие и вызывает функцию, которую вы ему дали, и она вспомнила ранее.
  6. Ваша вложенная функция устанавливает ответ true, что слишком поздно для условия 'if (response == true)', чтобы что-то с ним сделать.

Вы написали "// дождаться ответа" в качестве альтернативы, но нет кода на JavaScript, который вы могли бы написать, который действительно сделает это. Ваша функция должна вернуться, чтобы вернуть управление браузеру, прежде чем браузер сможет инициировать события щелчка в пользовательском интерфейсе jConfirm, которые заставляют обработку продолжаться.

Существуют способы заставить асинхронный код работать в синхронном контексте (и наоборот) - в частности потоки и сопрограммы (и их генераторы с ограниченными отношениями). Но в JavaScript нет ни одной из этих функций, поэтому вы должны написать свой код в соответствии с синхронной или асинхронной моделью, которую использует ваша библиотека.

8 голосов
/ 12 января 2009

Поскольку обратный вызов является асинхронным (по крайней мере, в том смысле, что он ожидает, что пользователь что-то сделает), может быть проще обработать то, что вам нужно внутри обратного вызова:

function confirm() {
    jConfirm('are you sure?', 'Confirmation Dialog', function(r) {
        if (r) doSomething();
    });
}

@ klogan [комментарии]

Я полагаю, вы получили это от здесь ?

На странице вы найдете ответ: (см. Использование )

Эти методы не возвращают те же значения, что и verify () и prompt (). Вы должны получить доступ к полученным значениям с помощью функции обратного вызова. (См. Демо для более подробной информации.)


@ klogan

Смысл, который я пытаюсь подчеркнуть, заключается в том, что на самом деле нет простого способа выполнить то, что вы хотите. Вы пытаетесь сопоставить процедурное и событийное программирование - что-то, что JavaScript не помогает вам делать.

Самое простое (хотя рискованное ) решение - использовать псевдо-бесконечный цикл. Но если callback никогда не вызывается, у вас теперь есть реальный бесконечный цикл. И, в зависимости от движка JavaScript, вы можете убить ожидание браузера.

Очко: Лучше всего избегать этого , пытаясь заставить событийно-управляемый процесс стать процедурным.

function confirm() {
    var result = false;
    var response = false;

    jConfirm('are you sure?', 'Confirmation Dialog',
      function(r) {
        result = r;
        response = true;
    });

    while(!response) continue; // wait
    return result;
}

5 голосов
/ 12 января 2009

Технически, да , но я бы не стал этого делать на веб-сайте.

Взгляните на Повествовательный JavaScript , основанный на Нарцисс .

Повествовательный JavaScript - это небольшое расширение языка JavaScript, которое позволяет блокировать асинхронные обратные вызовы событий. Это делает асинхронный код легко читаемым и понятным.

Селен использует эту технологию.


Обновление

Проверить JavaScript Strands :

JavaScript Strands добавляет сопрограмму и совместная поддержка потоков Язык JavaScript для включения блокировки возможности для асинхронного события Обратные вызовы. Это делает код, который много использует асинхронную операцию более линейный, читаемый и управляемый. Strands построен на повествовании JavaScript, написанный Нилом Миксом, и большая часть повествовательного JavaScript имеет остались в берегах, включая большую часть эта документация.

В JavaScript ваш код не может просто ждать, пока событие не произойдет - событие всегда должно обрабатываться отдельный, асинхронный обработчик событий. Иногда это хорошо, но часто заставляет то, что должно быть простым последовательность высказываний в корявом искажения. Это также ломает способность заключать в капсулу функциональность потому что вызывающие функции должны знать предоставить обработчик обратного вызова. Пряди предоставляет возможность приостановить и возобновить темы исполнения. выполнение может приостановить возобновление, когда событие законченный. Это позволяет вам писать трудно читаемое асинхронное событие обработка в простой, линейной, читабельной код, который инкапсулирует реализацию.

0 голосов
/ 08 марта 2012

Думайте о обратных вызовах как об отправке сообщений, и это приведет к улучшению структуры вашего кода.

0 голосов
/ 10 января 2012

Эта штука работает. Нуждается в jQuery.

function myconfirm(kyssa, elm, e){ // neG
    if(jQuery('#confirmquestion').data('result')){
        var V = jQuery('#confirmquestion').data('result');
        jQuery('#confirmquestion').remove(); 
        return V == 'Y' ? true : false;         
    }else if(!jQuery('#confirmquestion').length){
        jQuery('body').append('<div id="confirmquestion">'+
        '<h4>Kinnitus</h4>'+
        '<div id="kyssa">'+kyssa+'</div>'+
        '<center>'+
        '<button onclick="jQuery(\'#confirmquestion\').data(\'result\', \'Y\');">Jah</button>&nbsp;'+
        '<button onclick="jQuery(\'#confirmquestion\').data(\'result\', \'N\');">Ei</button></div>'+
        '</center>');
        jQuery('#confirmquestion button').click(function(){
            jQuery(elm).trigger(e.type);
        })
    }       
    return false;
}

onChange="if(myconfirm(\'Saada kiri: \'+jQuery(this).find(\'option:selected\').html()+\' ?\', this, event)) { ... }"

CSS

#confirmquestion{
    border:1px solid #999;
    background:white;
    padding-bottom: 30px;
    position:fixed;
    width:300px;
    font-size:12px;
    top:45%;
    left:50%;
    margin-left:-150px;
}

#confirmquestion h4 {
    background:blue;
    color:white;
    margin:0;
    padding: 2px 5px;
    border-bottom:#777; 
    text-align:center;
}

#confirmquestion #kyssa {
    padding: 30px 25px;
}
0 голосов
/ 11 октября 2011

Как сказали парни, пути нет! но ... как мы обычно говорим в моей стране (Бразилия), le gambi:

мы можем сделать что-то вроде этого:

<h:commandLink styleClass="linkValor xExcluir" value="x"  
                     onclick="if(confirmar('Confirmar excluir.','Deseja realmente excluir este registro?', this)) return true; else return false;"
                     action="#{mBeanPesquisarLinhas.excluir}"/>

и JavaScript:

function confirmar(titulo, msg, elemento) { 

    if ($(elemento).attr('sim')) {      
        $(elemento).removeAttr('sim');      
        return true;
    } else if ($(elemento).attr('nao')) {       
        $(elemento).removeAttr('nao');      
        return false;
    } else {
        $("#dialog-confirm").html('<p>' + msg + '</p>').dialog({
            resizable : false,
            height : 200,
            modal : true,
            title : titulo,
            buttons : {
                "Sim" : function() {
                    $(this).dialog("close");
                    $(elemento).attr('sim', 'sim');
                    $(elemento).click();
                },
                "Não" : function() {
                    $(this).dialog("close");
                    $(elemento).attr('nao', 'nao');
                    $(elemento).click();
                }
            }
        });
    }

    return false;
}

это та же проблема, но с использованием jquery-ui.

Пока, и я надеюсь, что это может кому-нибудь помочь.

0 голосов
/ 14 января 2009

Я думаю, что придумала возможное решение этой проблемы. Я читал эту статью: http://treasure4developer.wordpress.com/2008/06/23/calling-postback-event-from-javascript/

По сути, идея заключается в том, что вы заставляете обратную передачу из javascript, сначала я обнаружил, что обратная передача будет работать, но не будет вызывать событие моей кнопки, но после прочтения статьи я обнаружил, что могу определить, является ли это обратной передачей JavaScript и просто вызовите метод для обработки

С уважением, DotnetShadow

0 голосов
/ 12 января 2009

Я бы предположил, что вам нужно получить ответ, подобный этому. Я не думаю, что вам нужен обратный звонок.

function confirm() {
        var response = jConfirm('are you sure?', 'Confirmation Dialog');
        if (response) {
            alert(result);
        }
        else {
            //wait for response
            alert('hi');
        }
    }
...