2017-02-10 3 views
1

Я написал небольшую программу, которая поможет мне понять, как выполнять вложенные асинхронные обещания в jquery.Вложенные асинхронные jquery обещания

Я хочу вызвать две задачи в последовательности. Первая задача имеет две подзадачи, которые также вызывается последовательно. Это все.

Хотя это работает, я сомневаюсь, был ли это лучший способ использовать обещания. Необходимость создания нового отложенного для каждой задачи ощущается как запах кода для меня. Например, было бы лучше передать один отложенный объект и использовать только это? Благодаря!

https://plnkr.co/edit/dyFFqqZhCVuhBYCuWjzm?p=preview

doTasks().then(function(arg) { 
    console.log(arg) 
}) 

function doTasks() { 
    var d = $.Deferred(); 
    task1().then(function(arg) { 
     console.log(arg) 
     task2().then(function(arg) { 
      console.log(arg) 
      d.resolve('all tasks are done') 
     }) 
    }) 
    return d.promise(); 
} 

function task1() { 
    var d = $.Deferred(); 

    console.log("starting task1...") 

    setTimeout(function() { 
     task1A().then(function() { 
      task1B().then(function() { 
       d.resolve('task1 is done') 
      }) 
     }) 
    }, 10); 

    return d.promise(); 
} 

function task1A() { 
    var d = $.Deferred(); 
    console.log("starting task1A...") 
    setTimeout(function() { 
     console.log(" resolving task1A...") 
     d.resolve(); 
    }, 1000); 
    return d.promise(); 
} 

function task1B() { 
    var d = $.Deferred(); 
    console.log("starting task1B...") 
    setTimeout(function() { 
     console.log(" resolving task1B...") 
     d.resolve(); 
    }, 1000); 
    return d.promise(); 
} 

function task2() { 
    var d = $.Deferred(); 
    console.log("starting task2...") 

    setTimeout(function() { 
     d.resolve('task2 is done'); 
    }, 1000); 
    return d.promise() 
} 

ответ

1

Да, это немного вонючий, чтобы создать много ненужных deferreds.

Вам не нужно создавать отложенные для ваших операций ajax. Если вы вернете обещание с помощью обработчика .then(), он автоматически привязан к предыдущему обещанию (таким образом, его упорядочивая), и все вызовы jquery ajax уже возвращают обещания. Поэтому вам не нужно создавать свои собственные обещания для операций ajax. И вы можете цепочки, а не гнезда, чтобы упорядочить ваши операции.

Фактически, создание отложенных или обещаний, когда вам это не нужно, называется promise anti-pattern. Вы хотите использовать и возвращать обещания, которые уже созданы, а не создавать новые. И, где это возможно, вы хотите связать свои обещания, а не гнездо.

Вот как вы можете сделать это в исполняемом фрагменте, не создавая ни одного отложенного, кроме одного места для обертывания setTimeout() в обещании. Очевидно, вы могли бы использовать намного меньше кода для всех своих задач, если бы создали для них повторно используемую функцию, но я предполагаю, что это просто заполнители для реальных операций async, поэтому я оставлю их как есть (за исключением использования общий delay() функция).

doTasks().then(function(arg) { 
 
    console.log("everything done"); 
 
}) 
 

 
function doTasks() { 
 
    return task1().then(function(arg) { 
 
     console.log(arg); 
 
     return task2().then(function(arg) { 
 
      console.log(arg) 
 
      return arg; 
 
     }) 
 
    }) 
 
} 
 

 
// make promise version of setTimeout() in one central place 
 
// that can then be used elsewhere 
 
function delay(t) { 
 
    return $.Deferred(function(def) { 
 
     setTimeout(function() { 
 
      def.resolve(); 
 
     }, t); 
 
    }).promise(); 
 
} 
 

 
function task1() { 
 
    console.log("starting task1...") 
 
    return delay(10).then(function() { 
 
     return task1A(); 
 
    }).then(function() { 
 
     return task1B(); 
 
    }); 
 
} 
 

 
function task1A() { 
 
    console.log("starting task1A...") 
 
    return delay(1000).then(function() { 
 
     console.log(" resolving task1A...") 
 
     return "done task1A"; 
 
    }); 
 
} 
 

 
function task1B() { 
 
    console.log("starting task1B...") 
 
    return delay(1000).then(function() { 
 
     console.log(" resolving task1B...") 
 
     return "done task1B"; 
 
    }); 
 
} 
 

 
function task2() { 
 
    console.log("starting task2...") 
 
    return delay(1000).then(function() { 
 
     console.log(" task2 is done") 
 
     return "done task2"; 
 
    }); 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

2

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

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

Вы даже можете создать функцию, которая выведет что-то и снова вернет обещание.

Это позволит вам цепочку многого вместе:

doTasks().then(say.bind(null, 'all done')); 
 

 
function say(msg) { 
 
    console.log(msg); 
 
    return $.Deferred().resolve(msg).promise(); 
 
} 
 

 
function doTasks() { 
 
    return task1().then(task2); 
 
} 
 

 
function delay(ms) { // one function for delaying as a promise 
 
    var d = $.Deferred(); 
 
    setTimeout(d.resolve.bind(null, ' delay completed'), ms); 
 
    return say('starting delay of ' + ms + ' milliseconds...') 
 
     .then(d.promise).then(say); 
 
} 
 

 
function task1() { 
 
    return say('starting task1...').then(delay.bind(null, 10)) 
 
     .then(task1A).then(task1B).then(say.bind(null, 'task1 done')); 
 
} 
 

 
function task1A() { 
 
    return say('starting task1A...').then(delay.bind(null, 1000)) 
 
     .then(say.bind(null, ' resolving task1A...')); 
 
} 
 

 
function task1B() { 
 
    return say('starting task1B...').then(delay.bind(null, 1000)) 
 
     .then(say.bind(null, ' resolving task1B...')); 
 
} 
 

 
function task2() { 
 
    return say('starting task2...').then(delay.bind(null, 1000)) 
 
     .then(say.bind(null, 'task2 done')); 
 
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

+0

Почему бы вы предоставить этот ответ, когда мой ответ (от 20 минут раньше) в значительной степени обеспечивает всю ту же информацию? – jfriend00

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