Как я могу заставить это обещание выдать конкретные ошибки? - PullRequest
0 голосов
/ 24 мая 2018

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

У меня есть этот фрагмент обещания: все:

 Promise.all(receivedObjs.arrayCMsIds.map(cmid => 
                    server.writeAttachedCMinfo(invId,cmid)))
                            .then(function (results) { // for promise all
                                return res.json(apiHelp.success(results,"success"));

                            }).catch(function (error) {
                                res.json(apiHelp.error(error, error));
                            });

И эта длинная и сложная функция writeAttachedCMinfo:

    server.writeAttachedCMinfo = function (invId,cmid) {
    return new Promise(function (resolve, reject) {


        console.log("writeAttachedCMinfo");
        console.log("invoiceId " + invId);
        console.log("cmid "+ cmid);

        var invoiceId = JSON.stringify(invId);
        var cmId = JSON.stringify(cmid);
        var invIdString = invoiceId;
        var cmIdString = cmId;

        invIdString = invIdString.slice(1, -1);
        cmIdString = cmIdString.slice(1, -1);

        var projection = 'gwCode certifiedInvoiceAmount buyerReference supplierReference invoiceNo invoiceSerialNo invoiceFiles creditMemos';
        ubiqInvoice.findById(invIdString, projection).then(function (dbInvoice) {

            var intInvCertifiedAmount = parseInt(dbInvoice.certifiedInvoiceAmount);


            creditMemo.findById(cmIdString).then(function (dbCreditMemo) {
                var intCreditMemoAmount = parseInt(dbCreditMemo.creditMemoAmount);

                if (intInvCertifiedAmount <= intCreditMemoAmount) {

                    console.log('cm bigger than invoice')

                    return new Error ('CMisbiggerThanInvoice');
                }

                if (dbCreditMemo.isAssociated) {

                    return new Error ('CMisAssociated');
                }

                if (dbInvoice.gwCode === "100000000000"
                    || dbInvoice.gwCode === "110000000000"
                    || dbInvoice.gwCode === "111200000000"
                    || dbInvoice.gwCode === "111100000000"
                    || dbInvoice.gwCode === "111110000000"
                ) { 

                    var creditMemoEntry = {

                        id: guid.create().value,
                        batchId: dbCreditMemo.batchId,
                        invoiceId: dbInvoice._id,
                        recordTypeCode: "CM",
                        buyerReference: dbInvoice.buyerReference,
                        supplierReference: dbInvoice.supplierReference,
                        creditMemoNo: dbCreditMemo.creditMemoNo,
                        creditMemoIssuingDate: dbCreditMemo.creditMemoIssuingDate,
                        creditMemoEffectiveDate: dbCreditMemo.creditMemoEffectiveDate,
                        lastModificationDate: dbCreditMemo.lastModificationDate,
                        currencyCode: dbCreditMemo.currencyCode,
                        creditMemoAmount: dbCreditMemo.creditMemoAmount,
                        hashCode: dbCreditMemo.hashCode,
                        description: dbCreditMemo.description,
                        uploadDate: dbCreditMemo.uploadDate,
                        isAssociated: true,
                    }


                    dbInvoice.creditMemos.push(creditMemoEntry);
                    dbInvoice.certifiedInvoiceAmount = dbInvoice.certifiedInvoiceAmount - dbCreditMemo.creditMemoAmount;
                    dbInvoice.save();


                    dbCreditMemo.isAssociated = true;

                    dbCreditMemo.save();

                    resolve(dbInvoice)


                }
                else { return new Error ('wrongggwcode'); }

    })

        });

    }), function (error) {
        console.log("error: " + error);
    }

}

Моя цель - вызвать ошибку в первом случаеусловий if не выполнены, и я хочу передать ошибку клиенту в форме настраиваемого сообщения, чтобы я мог использовать его на клиенте для отображения различных ошибок, таких как «CMisbiggerThanInvoice»

if (intInvCertifiedAmount <= intCreditMemoAmount) {

                        console.log('cm bigger than invoice')

                        return new Error ('CMisbiggerThanInvoice');
                    }

Я просто пытаюсь выяснить, как передать ошибку от функции writeAttachedCMinfo в .catch (функцию (ошибку)) promise.all, но она не работает, обещание. Всегда возвращает успех, даже если один изесли условия не выполняются.

Я пытался отклонить ('CMisbiggerThanInvoice'), отклонить (новая ошибка ('CMisbiggerThanInvoice') ... ... все то же самое.

как я могу на самом деле форсироватьфункция обещания для возврата ошибки ?

Ответы [ 2 ]

0 голосов
/ 24 мая 2018

В server.writeAttachedCMinfo() главное:

Кроме того, поскольку существует только один invId, фактически существует только один dbInvoice, и его не нужно извлекать снова и сноваиз базы данных при каждом вызове server.writeAttachedCMinfo ().На самом деле его не нужно извлекать снова и снова, иначе каждый dbInvoice.save() может перезаписать ранее сохраненные данные в рамках одной и той же транзакции.Будет безопаснее накапливать все creditMemos и постепенно уменьшать certifiedInvoiceAmount в одном dbInvoice объекте, а затем выполнять один `dbInvoice.save ().

server.writeAttachedCMinfo = function(dbInvoice, cmid) {
    return creditMemo.findById(JSON.stringify(cmid).slice(1, -1))
    .then(dbCreditMemo => {
        if(parseInt(dbInvoice.certifiedInvoiceAmount) <= parseInt(dbCreditMemo.creditMemoAmount)) {
            throw new Error('CMisbiggerThanInvoice');
         // ^^^^^
        }
        /* all sorts of synchronous stuff */
        /* all sorts of synchronous stuff */
        /* all sorts of synchronous stuff */
        return dbCreditMemo; // deliver dbCreditMemo via returned Promise
    });
}

Теперь, ввызывающий абонент:

  • ubiqInvoice.findById() можно вызвать один раз.
  • выполнить проверки на dbInvoice и сбросить при ошибке.
  • pass dbInvoice, а неinvId до server.writeAttachedCMinfo() при каждом вызове.
  • все сохранение можно сделать здесь, а не в server.writeAttachedCMinfo().

Как следствие, вызывающая сторона включает часть кода, который был в server.writeAttachedCMinfo():

ubiqInvoice.findById(JSON.stringify(invId).slice(1, -1), 'gwCode certifiedInvoiceAmount buyerReference supplierReference invoiceNo invoiceSerialNo invoiceFiles creditMemos')
.then(dbInvoice => {
    if(dbCreditMemo.isAssociated) {
        throw new Error('CMisAssociated');
     // ^^^^^
    }
    if(dbInvoice.gwCode === '100000000000'
        || dbInvoice.gwCode === '110000000000'
        || dbInvoice.gwCode === '111200000000'
        || dbInvoice.gwCode === '111100000000'
        || dbInvoice.gwCode === '111110000000'
    ) {
        return Promise.all(receivedObjs.arrayCMsIds.map(cmid => {
            return server.writeAttachedCMinfo(dbInvoice, cmid)
            .catch(error => {
                console.log(error);
                return null;
            });
        }))
        .then(dbCreditMemos => {
            return Promise.all(dbCreditMemos.map(memo => {
                return memo ? memo.save() : null;
            }))
            .then(() => dbInvoice.save())
            .then(() => {
                res.json(apiHelp.success(dbInvoice, 'success'));
            });
        });
    } else {
        throw new Error('wrongggwcode');
     // ^^^^^
    }
})
.catch(error => {
    console.log('error: ' + error);
    res.json(apiHelp.error(error, error));
});

Вся область вокруг ошибок отлова / обработки, возникающих из server.writeAttachedCMinfo(), требуетбольше мыслейС одной стороны, вы можете захотеть сохранить успешные субтранзакции и поглотить ошибки (как указано выше), а с другой стороны, вы можете захотеть, чтобы любой отдельный сбой не приводил к сохранению ничего.

Другое соображение заключается в том, должны ли server.writeAttachedCMinfo() звонки выполняться последовательно, что будет контролировать приоритет, с помощью которого суб-транзакции получают доступ к кредитному балансу.В настоящее время, при параллельных запросах, это немного бесплатно для всех.

Это затрагивает немного больше, чем заданный вопрос, но, надеюсь, это будет полезно.

0 голосов
/ 24 мая 2018

В контексте обещания вы должны на самом деле выдать ошибку:

throw new Error('wrongggwcode');

Если это выполняется в обратном вызове конструктора обещания или then обратном вызове, его можно перехватить с помощью метода catch (или второй аргумент then) и аргумент обратного вызова, который вы передаете ему, будет ошибкой (объект).

Вызов reject изнутри обратного вызова then, очевидно, не будет работать, так как вытам нет доступа к reject, но он будет работать в режиме обратного вызова конструктора обещаний.

Простой пример:

new Promise((resolve, reject) => {
    setTimeout( () => reject(new Error('this is an error')) );
}).then( (value) => console.log('resolved with ' + value) )
.catch( (error) => console.log('error message: ', error.message) );

Вложенность

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

Так что в вашем случае сделайте следующее:

return creditMemo.findById( ....
//^^^^

По той же причине вам нужно сделать:

return ubiqInvoice.findById( ....
//^^^^

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

Положение обработчика ошибок

Обработчик ошибок размещается внеправильная позиция;на самом деле вы используете оператор запятой.Короче говоря, у вас есть это в вашем коде:

new Promise(function (resolve, reject) {
    // ... //
}), function (error) {
    console.log("error: " + error);
}

Функция после запятой никогда не выполняется, так как она не является аргументом для вызова метода.Он просто стоит за запятой.

Вам нужен вызов метода catch для нового обещания и каскадная ошибка там, чтобы Promise.all также получал отклонение:

return new Promise(function (resolve, reject) {
    // ... //
}).catch(function (error) {
    console.log("error: " + error);
    throw error; // cascade it
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...