2016-01-28 2 views
0

В одной из моих функций beforeSave мне нужно проверить ряд условий, прежде чем отвечать на них с успехом или ошибкой.Очистка кода спагетта с обещаниями

Проблема заключается в том, мой код кажется очень грязный, а иногда успех/ошибка не называется:

Parse.Cloud.beforeSave("Entry", function(request, response) { 
    var entry = request.object; 
    var contest = request.object.get("contest"); 

    entry.get("user").fetch().then(function(fetchedUser) { 
     contest.fetch().then(function(fetchedContest) { 
      if (fetchedUser.get("fundsAvailable") < fetchedContest.get("entryFee")) { 
       response.error('Insufficient Funds.'); 
      } else { 
       fetchedContest.get("timeSlot").fetch().then(function(fetchedTimeSlot) { 
        var now = new Date(); 
        if (fetchedTimeSlot.get("startDate") < now) { 
         response.error('This contest has already started.'); 
        } else { 
         contest.increment("entriesCount"); 
         contest.increment("entriesLimit", 0); //have to do this, otherwise entriesLimit is undefined in save callback (?) 

         contest.save().then(function(fetchedContest) { 
          if (contest.get("entriesCount") > contest.get("entriesLimit")) { 
           response.error('The contest is full.'); 
          } else { 
           response.success(); 
          } 
         }); 
        } 
       }); 
      } 
     }); 
    }); 
}); 

Я пытался узнать обещания навести порядок в этом, и здесь был мой (не удалось) попытка:

Parse.Cloud.beforeSave("Entry", function(request, response) { 
    var entry = request.object; 
    var contest = request.object.get("contest"); 

    entry.get("user").fetch().then(function(fetchedUser) { 
     contest.fetch().then(function(fetchedContest) { 
      if (fetchedUser.get("fundsAvailable") < fetchedContest.get("entryFee")) { 
       response.error('Insufficient Funds.'); 
      } 
      return fetchedContest; 
     }); 
    }).then(function(result) { 
     result.get("timeSlot").fetch().then(function(fetchedTimeSlot) { 
      var now = new Date(); 

      if (fetchedTimeSlot.get("startDate") < now) { 
       response.error('This contest has already started.'); 
      } 
     }); 
    }).then(function() { 
     contest.increment("entriesCount"); 
     contest.increment("entriesLimit", 0); 
     contest.save().then(function(fetchedContest) { 
      if (contest.get("entriesCount") > contest.get("entriesLimit")) { 
       response.error('The contest is full.'); 
      } 
     }); 
    }).then(function() { 
     response.success(); 
    }, function(error) { 
     response.error(error); 
    }); 
}); 

Любая помощь или примеры того, как использовать обещания для этого, будут высоко оценены. Ясно, что я не совсем понимаю, как они работают синтаксически.

+0

Это будет намного проще, если вы опишете данные. Лучший способ сделать это - вставить строки заголовков из браузера данных для каждого объекта (достаточно широко, чтобы включить столбцы, на которые ссылается вопрос). – danh

+0

Чтобы задать вопрос и ответы в каком-то контексте, вы можете прочитать ** [Как получить доступ к предыдущим результатам в цепочке .then()?] (Http://stackoverflow.com/questions/ 28250680 /) **. Исходный код вопроса записывается в ** [Nesting (and) closures] (http://stackoverflow.com/a/28250687/3478010) ** стиле, в то время как попытка очистить не соответствует ни одному из предложенных узоры. Оба ответа ниже: ** [Mutable Contextual State] (http://stackoverflow.com/a/28250700/3478010) **, который по указанным причинам действительно следует избегать. –

+0

Лично я бы либо придерживался оригинального вложенного решения, либо принял ** [Break the chain] (http://stackoverflow.com/a/28250704/3478010) **, в котором после нескольких строк преамбулы вы закончит с простой структурой управления формы 'Parse.Promise.when (p1, p2, p3). then (function (r1, r2, r3) {...}), затем (...);' , Я думаю, это примерно так же аккуратно, как вы могли это сделать. Если вы все еще заинтересованы, я отправлю полный ответ. –

ответ

1

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

Parse.Cloud.beforeSave("Entry", function(request, response) { 
    var entry = request.object; 
    var contest = request.object.get("contest"); 

    var fetchedUser, fetchedContest; 
    var errorMessage; 

    entry.get("user").fetch().then(function(result) { 
     fetchedUser = result; 
     return contest.fetch(); 
    }).then(function(result) { 
     fetchedContest = result; 
     return fetchedContest.get("timeSlot").fetch(); 
    }).then(function(fetchedTimeSlot) { 
     // now we have all the variables we need to determine validity 
     var now = new Date(); 
     var hasSufficientFunds = fetchedUser.get("fundsAvailable") >= fetchedContest.get("entryFee"); 
     var contestNotStarted = fetchedTimeSlot.get("startDate") >= now; 
     if (hasSufficientFunds && contestNotStarted) { 
      contest.increment("entriesCount"); 
      contest.increment("entriesLimit", 0); //have to do this, otherwise entriesLimit is undefined in save callback (?) 
      return contest.save(); 
     } else { 
      errorMessage = (hasSufficientFunds)? 'This contest has already started.' : 'Insufficient Funds.'; 
      return null; 
     } 
    }).then(function(result) { 
     if (!result) { 
      response.error(errorMessage); 
     } else { 
      if (contest.get("entriesCount") > contest.get("entriesLimit")) { 
       response.error('The contest is full.'); 
      } else { 
       response.success(); 
      } 
     } 
    }, function(error) { 
     response.error(error); 
    }); 
}); 

Обратите внимание, как мы никогда не оставить response.anything() болтается, мы всегда ясно, что течет к следующему обещанию через возвращение.

+0

Благодарим вас за такое подробное и прямолинейное объяснение. Теперь я понимаю обещания намного лучше, и этот код работает намного надежно, чем раньше. – vikzilla

1

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

Parse.Cloud.beforeSave("Entry", (request, response) => { 
    var entry = request.object, 
    , contest = request.object.get("contest") 
    , fetchedUser 
    , fetchedContest; 

    entry.get("user").fetch() 
    .then(_fetchedUser => { 
     fetchedUser = _fetchedUser; 
     return contest.fetch(); 
    }).then(_fetchedContest => { 
     fetchedContest = _fetchedContest; 
     if (fetchedUser.get("fundsAvailable") < fetchedContest.get("entryFee")) 
     return Promise.reject('Insufficient Funds.');  
     return fetchedContest.get("timeSlot").fetch(); 
    }).then(fetchedTimeSlot => { 
     var now = new Date(); 
     if (fetchedTimeSlot.get("startDate") < now) 
     return Promise.reject('This contest has already started.');  
     contest.increment("entriesCount"); 
     contest.increment("entriesLimit", 0); //have to do this, otherwise entriesLimit is undefined in save callback (?) 
     return contest.save(); 
    }).then(fetchedContest => { 
     if (contest.get("entriesCount") > contest.get("entriesLimit")) 
     return Promise.reject('The contest is full.');   
     response.success();   
    }).catch(response.error.bind(response)); 

}); 
+0

Я действительно новобранец с JS. Спасибо за объяснение, однако я немного смущен некоторыми вашими синтаксисами. До сих пор я знаком с написанием основного кода JS для облачного кода Parse; Я не видел использование синтаксиса типа «=>», поскольку вы используете его здесь. Это то, о чем я должен знать? – vikzilla

+0

@vikzilla, я не имел в виду неуважение (означало людей, новых для Promises), '=>' называется функцией стрелок, сокращением для анонимных функций, частью ES6/ES2015. Если вы хотите придерживаться ES5, замените 'a => {...}' на 'function (a) {...}' – mido