2016-10-25 3 views
1

Это мой первый опыт работы с асинхронным движением, и хотя я искал в Интернете и пытался использовать методы серии и водопада, мои результаты совпадают. Я думаю, что я довольно близок к тому, что эта работа правильная, но просто не могу заставить ее работать на 100%.асинхронный водопад не правильно сохраняется с mongoose

Я пытаюсь создать тест, основанный на параметрах времени и теста, отправленных с передней стороны. Основная проблема заключается в том, что последний метод внизу, который создает тест, проходит до среднего метода, который ищет вопросы , пример ответов, если они есть, а затем помещает его в массив объектов.

После завершения теста создается без вопросов, но он сохраняет время от первой функции. Первоначально (перед попыткой async) я завернул метод «new interviewtest» в 2sec setTimeout, и это сработало нормально, но я знаю, что есть лучший и эффективный способ сделать это.

exports.create = function(req) { 
console.log(req.body); 
var testTime = 0; 
var timer = req.body.timeValue; 
var testQuestions = req.body.category; 
var finalQuestions = []; 

async.waterfall([ 
    function(callback) { **add total time into one value to be saved in the test** 
     for (var i = 0; i < timer.length; i++) { 
      if (timer[i] !== '') { 
       testTime += parseInt(timer[i]); 
      } 
     } 
     callback(null,testTime); 
    }, 
    function(testTime,callback) { **find question and push it into array of objects** 
     for (var i = 0; i < testQuestions.length; i++) { 
      allTestQuestions.findById(testQuestions[i], function(err, result) { 
       var test = {}; 
       test.text = result.text; 
       test.answer = ''; 
       test.sample = result.sample; 
       finalQuestions.push(test); 
      }); 
     } 
     callback(null, testTime, finalQuestions); 
    }, 
    function(testTime, finalQuestions, callback) { **create new test** 
     new interviewTest({ 
      authCode: req.body.intAuthCode, 
      name: req.body.intName, 
      questions: finalQuestions, **questions** 
      assignedDate: new Date, 
      started: false, 
      startedTime: '1970', 
      completed: false, 
      completedTime: '1970', 
      time: testTime, 
      timePerQuestion: [] 
     }).save(function(err, res) { 
      console.log(err); 
      if (!err) { console.log(res + " saved!"); } 
     }); 

     callback(null, 'done'); 
    } 
], function (err, result) { 
    if (err) { callback(err); } 
    console.log(result); 
}); 
} 
+0

Вы всегда вызове 'callback' сразу, несмотря на то, начал асинхронная функция. Вам необходимо передать обратный вызов, например '.save (callback);'! И для этого цикла вам нужно вложить «async.map». – Bergi

+0

'if (err) {callback (err); } 'не имеет смысла. В этой области нет «обратного вызова». – Bergi

ответ

1

В средней функции у вас есть цикл for, который вызывает базу данных, и вы вызываете обратный вызов вне цикла. Он должен быть завернут в другую функцию async. Попробуйте async.each или как предполагает Берги, async.map

async.waterfall([ 
    function(callback) { 
     for (var i = 0; i < timer.length; i++) { 
      if (timer[i] !== '') { 
       testTime += parseInt(timer[i]); 
      } 
     } 
     callback(null,testTime); 
    }, 
    function(testTime,callback) { 
    async.each(testQuestions, function(tQuestion, eachCallback){ 
     allTestQuestions.findById(tQuestion, function(err, result) { 
      if(err){ 
       // you can either eachCallback(err) or just console.log it and keep going 
      } 
      var test = {}; 
      test.text = result.text; 
      test.answer = ''; 
      test.sample = result.sample; 
      finalQuestions.push(test); 
      eachCallback() 
     }) 
    }, function(err, result){ 
     callback(null, testTime, finalQuestions); 
    }) 
}, 
    function(testTime, finalQuestions, callback) { 
     new interviewTest({ 
      authCode: req.body.intAuthCode, 
      name: req.body.intName, 
      questions: finalQuestions, 
      assignedDate: new Date, 
      started: false, 
      startedTime: '1970', 
      completed: false, 
      completedTime: '1970', 
      time: testTime, 
      timePerQuestion: [] 
     }).save(function(err, res) { 
       console.log(err); 
       if (!err) { console.log(res + " saved!"); } 
       callback(null, 'done'); //call here 
      }); 

     // callback(null, 'done'); this should always be called inside the callback function 
    } 
], function (err, result) { 
    if (err) { callback(err); } 
    console.log(result); 
}); 
+1

Вы действительно должны использовать 'async.map' вместо' async.each'. Это даст вам «finalQuestions» неявно. – Bergi

+0

Это, кажется, поместило меня на правильный трек, однако теперь я получаю сообщение об ошибке «Invalid select(). Должен быть строкой или объектом». После поиска, я добавил async.map вместо foreach. – reedb89

+0

ошибочно 'allTestQuestions.findById' выполнял две функции обратного вызова. Обновлен ответ. –

0

Ответный находятся вне функции асинхронной (за исключением, и findById), не СТГ, как это:

function(testTime,callback) { **find question and push it into array of objects** 
    for (var i = 0; i < testQuestions.length; i++) { 
     allTestQuestions.findById(testQuestions[i], function(err, result) { 
      ... 
      finalQuestions.push(test); 
      if(finalQuestions.length == testQuestions.length) 
       return callback(null, testTime, finalQuestions); 
     }); 
    } 

}, 
function(testTime, finalQuestions, callback) { **create new test** 
    new interviewTest({ 
     ... 
    }).save(function(err, res) { 
     console.log(err); 
     if (!err) { console.log(res + " saved!"); } 
     callback(null, 'done'); 
    }); 
} 
Смежные вопросы