Подтвердить что ты не робот

Последовательный вызов с использованием взаимосвязи внутри цикла

Я хочу выполнить синхронную работу с помощью promise. У меня есть цикл, который передает данные, которые нужно вставить в функцию insert, и после вставки одной строки я хочу проверить no. строк существует в таблице, поэтому я выполняю операцию select.

Но проблема в том, что есть 3 записи, тогда она вставляет все 3 записи, после чего моя функция выбора выполняется. то, что я хочу, после того, как вызывается функция выбора одной записи.

вот мой псевдо-код, поскольку весь код включает в себя множество операций

for(var i=0; data.length ; i++){

 self.executeFeedbackTrack(data);

}


executeFeedbackTrack:function(callInfo){
    var self=this;
   return  self.insertFeedbackTrack(callInfo).then(function(data){

                console.log("insertFeedbackTrack status "+status);

        return self.getFeedbackTrack();

    });
},

getFeedbackTrack :function(){

    return new Promise(function(resolve,reject){
         var objDBFeedbackTrack = new DBFeedbackTrack();
        objDBFeedbackTrack.selectFeedbackTrack(function(arrayCallRegisters){
            if(arrayCallRegisters){

            console.log("notification.js no. of feedbacks "+arrayCallRegisters.length);

            resolve(arrayCallRegisters.length);

            }

        });
    });


},
insertFeedbackTrack :function(callInfo){

return new Promise(function(resolve,reject){
     var objDBFeedbackTrack = new DBFeedbackTrack();
     objDBFeedbackTrack.insertFeedbackTrack(callInfo.callNumber,callInfo.callServiceType,function(status){

             resolve(status);
            $('#loader').hide();

     });
});

}
4b9b3361

Ответ 1

Это можно решить, используя очень удобную JS-библиотеку Ramda. Концепция заключается в использовании двух методов: один R.partial, а другой R.pipeP.

Сначала создайте массив promises из массива data, как показано ниже.

var promises = data.map(function(i) {
  return R.partial(sample, [i])
});

Затем вы можете передать это обещание R.pipeP, чтобы он мог выполняться один за другим. как показано ниже.

var doOperation = R.pipeP.apply(this, promises)

Пожалуйста, выполните следующие фрагменты.

// Sample promise returning function
function sample(d) {
  return new Promise(function(resolve, reject){
    setTimeout(function() {
      console.log('resolved for:' + d);
      resolve(d);
    }, 1000)
  })
}

// Sample data
var data = [1, 2, 3, 4, 5]

// Converting data array to promise array
var promises = data.map(function(i) {
  return R.partial(sample, [i])
});

var doOperation = R.pipeP.apply(this, promises)
doOperation();
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Ответ 2

Предыдущий ответ хорош, но если вы используете nodejs или babel, или используете только современные браузеры. Вы можете использовать пару с асинхронным ожиданием, это материал es8.

let insertFeedbackTrack = function(){ return new Promise(/***/)};
let getFeedbackTrack = function(){ return new Promise(/***/)};
let processResult = async function(data){
   let feedbacks = [];
   for(let i=0;i<data.length;i++){
      let insertedResult = await insertFeedbackTrack(data[i]);//perhaps you will return an id;
      let feedbackTrack = await getFeedbackTrack(insertedResult.id);
      feedbacks.push(feedbackTrack);
   }
   return feedbacks;
} 

processResult(data).then(/** do stuff */)

Ответ 3

Мне кажется, что это вызвано выполнением ряда асинхронных вставок и предполагается, что get of insert n (внутри .then()) вызывается до выполнения insert n+1. Однако я не знаю никакой такой гарантии, в JavaScript; все, что я знаю, это то, что then n будет вызываться после insert n, а не то, что он будет вызываться до insert n+1.

Я предлагаю избегать этого сочетания традиционного и обратного кода и вместо этого ставить шаг итерации внутри getFeedbackTrack().then. Предполагая, что это понимание проблемы правильное, тогда должно работать следующее:

function iterate(i) {
    if (i < data.length) {
        obj.insertFeedbackTrack(data[i]).then(function(insertResult) {
            self.getFeedbackTrack().then(function(getResult) {
                // this line is the important one, replacing the `for` loop earlier
                iterate(i+1);
            });
        });
    }
}

iterate(0);

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

Естественно, вы также можете изменить структуру, чтобы использовать цепочку .then вместо вложенной; Я использовал вложенные, а не цепочки, чтобы подчеркнуть порядок обратных вызовов.

Ответ 4

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

for(var i = 0; i < order.tasks.length; i++){
        if(order.tasks[i].customer_id === 0){
          var name = order.tasks[i].customer_name.split(" ")
          const customers = yield db.queryAsync(
            `INSERT INTO customers(
              business_id)
             VALUES(?)
            `,[order.business_id])
        }
      }

Или иначе я использую функции самозапуска в случае обратных вызовов.

var i = 0;
(function loop() {
    if (i < data.length) {
        task_ids1.push([order.tasks[i].task_id])
        i++;
        loop();
    }
}());

Ответ 5

Вот как я буду последовательно вызывать promises в цикле (я использую ES7). Сначала определим некоторые основные данные:

const data = [0,1,2,3];

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

const promiseExample = (item) =>
  new Promise((res) => {
    setTimeout(() => {
      console.log('resolved ', item);
    res(item);
  }, 1000);
});

Теперь создадим массив из promises. Что делает следующая строка кода: для каждого элемента в массиве данные возвращают обещание factory. Обещание factory - это функция, которая обертывает определенное обещание без его запуска.

const funcs = data.map(item => async () => await promiseExample(item));

Теперь начинается код. Нам нужна функция, которая выполняет фактическую сериализацию. Поскольку он должен обрабатывать массив promFactories, я разделяю его на две функции: одну для сериализации единого обещания и одну для обработки массива promFactories.

const serializePromise = promiseFactoryList =>
  promiseFactoryList.reduce(serialize, Promise.resolve([]));

const serialize = async (promise, promiseFactory) => {
  const promiseResult = await promise;
  const res = await promiseFactory();
  return [...promiseResult, res];
};

Теперь вы можете просто называть его следующим образом:

serializePromise(funcs).then(res => {
    console.log('res', res);
});

Как вы можете видеть, код довольно простой, элегантный, функциональный и не нуждается в какой-либо внешней зависимости. Надеюсь, это ответит на ваш вопрос и поможет вам!

const serializePromise = promiseFactoryList =>
  promiseFactoryList.reduce(serialize, Promise.resolve([]));

const serialize = async (promise, promiseFactory) => {
  const promiseResult = await promise;
  const res = await promiseFactory();
  return [...promiseResult, res];
};

const data = [0,1,2,3];

const promiseExample = (item) =>
  new Promise((res) => {
	setTimeout(() => {
	  console.log('resolved ', item);
	  res(item);
    }, 1000);
  });

const funcs = data.map(item => async () => await promiseExample(item))

serializePromise(funcs).then(res => {
  console.log('res', res);
});