Попытка сломать цепочку обещаний jQuery с помощью .then,.fail и .reject

Обновление: эта проблема была результатом jQuery 1.7 vs 1.8. Никогда не используйте promises в 1.7 beacuse, они не связаны с возвратом обещания внутри .then. 1.8 похоже, что они не испортили его.

http://jsfiddle.net/delvarworld/28TDM/

// make a promise
var deferred = $.Deferred();
promise = deferred.promise();

// return a promise, that after 1 second, is rejected
promise.then(function(){
    var t = $.Deferred();
    setTimeout(function() {
        console.log('rejecting...');
        t.reject();
    }, 1000);

    return t.promise();
});

// if that promise is successful, do this
promise.then(function() {
    console.log('i should never be called');
})

// if it errors, do this
promise.fail(function() {
    console.log('i should be called');
});

deferred.resolve();

Ожидаемое: "Я должен быть вызван"

Фактически: "я никогда не должен называться"

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

Я иду из библиотеки NodeJS Q, поэтому сначала попробовал его с .then. Однако изменение его на .pipe не влияет.

Ответ 1

Вы не переопределяете значение promise, попробуйте следующее:

http://jsfiddle.net/28TDM/1/

var deferred = $.Deferred();
promise = deferred.promise();

promise = promise.then(function(){
    var t = $.Deferred();
    setTimeout(function() {
        console.log('rejecting...');
        t.reject();
    }, 1000);

    return t.promise();
});

promise.then(function() {
    console.log('i should never be called');
})

promise.fail(function() {
    console.log('i should be called');
});

deferred.resolve();

По-видимому, он работает, как вы думали, он сделал, он просто не документирован https://api.jquery.com/deferred.then. Очень круто. Это новая функциональность, добавленная в jQuery 1.8.0, более вероятно, что они просто не будут обновлять документацию.

Ответ 2

ИМХО, ты ничего не цепляешь. Ваш второй .then прикреплен к тому же обещанию, что и первый .then прикреплен к.

Почему?

Обратите внимание, что then всегда будет RETURN новым обещанием, а не изменяет обещание, к которому оно привязано. Он не имеет побочного эффекта.

Например:

var promiseX = promiseA
                 .then(function() { return promiseB; })
promiseX.then(function() { return promiseC; });

promiseA не изменит свое значение после присоединения then; он будет сохраняться, как есть.

promiseX будет возвратным значением 1-го then, то есть promiseB.

Итак, второй then фактически привязан к promiseB.

И это именно то, что @Kevin B сделал в своем ответе.


Другое решение состоит в том, что, поскольку .then вернет новое обещание, вы можете связать функции .then, как показано ниже.

var promiseX = promiseA
                 .then(function() { return promiseB; })
                 .then(function() { return promiseC; });

На этот раз 1-й then прикреплен к promiseA и догадывается, к какому обещанию привязан второй then к?

Ты прав. Это promiseB, а не promiseA. Поскольку второй then фактически привязан к возвращаемому значению 1-го then, т.е. promiseB.

И, наконец, 2 then возвращает значение promiseX, поэтому promiseX равно promiseC.

Хорошо, вернитесь к вопросу OP. Следующий код - это мой ответ.

var deferred = $.Deferred();
promise = deferred.promise(); // this is the first promise

promise.then(function(){ // callbacks for 1st promise
    var t = $.Deferred();
    setTimeout(function() {
        console.log('rejecting...');
        t.reject();
    }, 1000);
    return t.promise(); // this is the 2nd promise
    // return $.Deferred().reject(); // To reject immediately.
}).then(function() { // callbacks for 2nd promise
    console.log('i should never be called');
}, function() {
    console.log('i should be called');
})

deferred.resolve();