2015-06-22 2 views
1

I цепь ряд обещаний:Отменить цепочку обещаний?

this.getData.then(this.getMoreData).then(this.getEvenMoreData); 

В какой-то момент пользователь может принять решение отменить запрос и попросить что-то другое.

Как я могу отменить распространение цепи?

+1

Что вы подразумеваете под "пользователем"? Это фрагмент кода, который выполняется как можно быстрее, как бы вы добавили здесь вмешательство пользователя? – tadman

+0

Сайт получает много данных. Если пользователь затем запрашивает другие данные, я хочу остановить получение текущего набора данных и их вывод. – panthro

+0

Так как же это получится? Есть ли объект состояния для этого запроса, который указывает, что он был отменен, например 'var state = {running: true}', и затем вы можете проверить 'if (state.running) {return this.getMoreData()}' по мере необходимости. – tadman

ответ

1

Вы должны были бы проверить состояние (о том, следует ли отменить или нет) внутри каждого цепного метода:

var userRequestedCancel = false; 

this 
    .getData() 
    .then(function() { 
    if(userRequestedCancel) { 
     return Promise.reject('user cancelled'); 
    } 

    return getMoreData(); 
    }) 
    .then(function() { 
    if(userRequestedCancel) { 
     return Promise.reject('user cancelled'); 
    } 

    return getEvenMoreData(); 
    }) 

Или, возможно, немного более элегантным способом (отредактированный передать контекст и аргументы в callback методы)

var currentReq = false; 
var userRequestedCancel = false; 
var shouldContinue = function(cb,args) { 
    if(userRequestedCancel) { 
     return Promise.reject('user cancelled'); 
    } 

    currentReq = cb.apply(this,args); 
    return currentReq; 
} 

var onCancel = function() { 
    userRequestedCancel = true; 
    currentReq && currentReq.abort(); 
} 

this 
    .getData() 
    .then(function() { 
    return shouldContinue(getMoreData,arguments); 
    }) 
    .then(function() { 
    return shouldContinue(getEvenMoreData,arguments); 
    }) 

Если вам нужно отменить текущий запрос, а также, что является своего рода тривиальное, установить текущее ajax запрос быть глобальной переменной, и что когда событие event устанавливает флаг userRequestedCancel в true, также отмените запрос ajax (см. отредактированный код выше)

+0

Asuming getData() - это некоторый запрос ajax, запрос должен быть прерван, когда ответ еще не получен. –

+0

@NickRussler - еще не концептуально сложно. См. Отредактированный код - сохраняйте ссылку на текущий запрос ajax и всякий раз, когда вы устанавливаете 'userRequestedCancel' значение' true' - также отмените последний запрос. – Adam

+1

yup, только что упомянули, потому что op сказал, что «сайт получает ** много данных ** [...]» –

0

От jquery forum:

Для обработки возможных ошибок приложения, я делаю следующее снова и снова: Скопировать код

var deferred = $.Deferred().done(stuff_to_do).fail(handle_application_error); 
$.post(url, params, function(data) { special_error_check(data, deferred) }, 'json'); 

special_error_check() видит если данные JSON содержит ошибку сообщений. Если это так, он вызывает отложенный.reject(). Если ошибок нет, вызывает overfer().

+0

Это не ответит на вопрос – panthro

+0

, почему бы и нет? Вы действительно прочитали мой ответ? –

0

Чтобы отменить цепочку обещаний, вам нужно выбросить ошибку. Просто ознакомьтесь с кодом ниже

function CancelError() { 
    this.message = 'Cancelled'; 
} 


obj 
    .then(function() { 
     throw new CancelError(); 
    }) 
    .catch(function(err) { 
     if (err instanceof CancelError) { 
      // Promise got cancelled 
     } 
     throw err; // throw the other mistakes 
    }); 
+0

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

0

Веселый вызов!

Не зная точно, какую задачу, запросить или обрабатывать вы запускаете И как пользователь может прервать указанный процесс, трудно рекомендовать любое решение для «разрыва» цепочки .then(...), не выполняя какого-либо взлома/трюка, .catch(...) отказ от обратного вызова.

Это, как говорится, см., Если этот пример вообще проливает свет.

Обратите особое внимание на функции makeInterruptablePromise и как она используется:

var bar = $('.progress-bar'); 
 
var h3 = $("h3"); 
 
var isEscape; 
 

 
function log(msg, replace) { 
 
    h3[replace ? 'html' : 'append'](msg + "<br/>"); 
 
} 
 

 
$(document).keydown(e => { 
 
    switch(e.keyCode) { 
 
    case 27: //ESCAPE 
 
     return isEscape = true; 
 
    case 32: //SPACE 
 
     return runDemo(); 
 
    } 
 
}); 
 

 
function makeInterruptablePromise(cbStatus) { 
 
    return new Promise((resolve, reject) => { 
 
    function loop() { 
 
     switch(cbStatus()) { 
 
     case 1: return resolve(); 
 
     case -1: return reject(); 
 
     default: requestAnimationFrame(loop); 
 
     } 
 
    } 
 
    //Don't forget to start the loop! 
 
    loop(); 
 
    }) 
 
} 
 

 

 
function runDemo() { 
 
    log("Wait for it... (ESC to interrupt, SPACE to replay)", true); 
 
    
 
    isEscape = false; 
 
    
 
    var timeToComplete = 2000; 
 
    var timeStart = Date.now(); 
 
    
 
    function updateBar() { 
 
    var timeDiff = Date.now() - timeStart; 
 
    var timePercent = timeDiff/timeToComplete; 
 
    TweenMax.set(bar, {scaleX: 1 - timePercent}); 
 
    return timePercent > 1; 
 
    } 
 
    
 
    makeInterruptablePromise(() => { 
 
    if(isEscape) return -1; 
 
    if(updateBar()) return 1; 
 

 
    return 0; 
 
    }) 
 
    .then(() => log("Inside *then* chain.")) 
 
    .catch(() => log("Skipped *then* chain!")) 
 
} 
 

 
runDemo(); //Run first time.
body { 
 
    background-color: #123456; 
 
    color: #fff; 
 
} 
 

 
.progress-bar { 
 
    display: block; 
 
    width: 200px; 
 
    height: 10px; 
 
    background-color: #88f; 
 
    transform-origin: top left; 
 
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.2/TweenMax.min.js"></script> 
 
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 

 
<div class="progress-bar"></div> 
 

 
<h3></h3>

То, что это по существу сводится к тому, это я передаю обратный вызов makeInterruptablePromise на «монитор «для 3 возможных статусов.

  • Если это 1: Это решает (входит в ваш «тогда»)
  • Если это -1: Он отвергает (перескакивает на свой «улов»)
  • В противном случае, он просто продолжает цикл, используя браузер requestAnimationFrame(...) метод.
    (по существу, setTimeout(...) калиброван для запуска на экран освежает).

Теперь, чтобы влиять как эти статусы изменения с течением времени, я продемонстрировал это с помощью ESCAPE как статус прерывания (-1) и таймер, который работает в течение 2 секунд. После завершения таймер возвращает статус (1).

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

Смежные вопросы