2017-06-14 5 views
2

Ich habe eine Reihe von Versprechen, die ich in testCard verkettet habe. Diese Methode benötigt eine stripe Kartennummer, holt das Token von stripe und spricht dann mit einer API eines Drittanbieters, die versucht, Einkäufe mit dieser Karte durchzuführen. Ich brauche testCard durch Schleifen durch ein Array von Kartennummern. Um dies zu tun, habe ich ein controller Objekt mit einer Methode testAllCards, die das Array von Zahlen übernimmt. Das Array wird in einer Konfigurationsdatei gespeichert.Nodejs versprechen alle nicht wie erwartet laufen

Ich führe dann den Code von der Befehlszeile mit node cli.js testAllCards.

Allerdings, wenn ich es ausführen, bekomme ich testAllCards has been run, bevor alle die meisten Versprechen gelöst haben. Ich vermisse hier offensichtlich etwas, kann aber nicht herausfinden, was es ist.

cli.js

const testAllCards =() => { 
    return controller.testAllCards(config.get('CARD_NUMBERS')) 
    .then((obj) => { 
     console.log('testAllCards has been run'); 
    }) 
    .catch((e) => { 
     console.log('testCards has been run with an error!'); 
     const _err = new ErrHandler(e, eTopicName, eSnsSubject); 
     _err.handle() 
     .then(() => { 
      console.log('Error has been sent with success to sns'); 
     }); 
    }); 
}; 

switch(process.argv[2]) { 
    case 'testAllCards': 
    testAllCards(); 
    break; 
    default: 
    console.log('Please run with `testAllCards`'); 

controller.js

//Tests response from API for different cards 
const testCard = (cardNum) => { 
    return new Promise((resolve, reject) => { 
    const expMonth = new Date().getMonth() + 1; 
    const expYear = new Date().getFullYear() + 2; 
    const cardObj = { 
     cardNum: cardNum, 
     expMonth: expMonth, 
     expYear: expYear 
    }; 
    let apiCardItem = ''; 
    return testRequestToApi('getStripeToken', 200, 299, cardObj) 
     .then((cardItem) => { 
     return testRequestToApi('postNewCard', 200, 299, JSON.parse(cardItem.body)); 
     }) 
     .then((apiCard) => { 
     apiCardItem = apiCard.body; 
     try { 
      apiCardItem = JSON.parse(apiCardItem); 
     } catch(e) { 
      console.log(e); 
     } 
     return testRequestToApi('sampleAddToCart', 200, 299); 
     }) 
     .then(() => { 
     return testRequestToApi('useFailingStripeCards', 400, 499, apiCardItem.id); 
     }) 
     .then(() => { 
     return testRequestToApi('deleteCard', 200, 299, apiCardItem.id); 
     }) 
     .then(() => { 
     resolve(); 
     }) 
     .catch((e) => { 
     reject(e); 
     }); 
    }); 
}; 

//Loops through the card numbers and runs the test command against them 
Controller.testAllCards = (cardsArray) => { 
    const items = cardsArray.map((cardNum) => { 
    return testCard(cardNum); 
    }); 
    return Promise.all(items); 
}; 

module.exports = Controller; 

Test-Anfrage-to-api.js

'use strict'; 

const checkStatus = require('./../utils/status-code-checker'); 
const formHeaders = require('./../utils/form-req-headers'); 
const request  = require('request'); 
const expObj = {}; 

//@requestType {string} - defines which headers and function name to use 
//@item {object} - defines item that is being used 
expObj.testRequestToApi = (requestType, lowerLimit, upperLimit, item) => { 
    return new Promise((resolve, reject) => { 
    const reqOps = formHeaders[requestType](item); 
    request(reqOps, (err, response, body) => { 
     if (err) { 
     const badRequest = { 
      ErrorMessage: err, 
      FuncName: requestType, 
      InternalError: true 
     }; 
     return reject(badRequest); 
     } 
     if (!checkStatus.checkRangeStatusCode(response.statusCode, lowerLimit, upperLimit)) { 
     console.log(JSON.stringify(body, null, 2)); 
     // Set a bad Status error object 
     let badStatus = { 
      StatusCode: response.statusCode, 
      ErrorMessage: body, 
      FuncName: requestType, 
      InternalError: false 
     }; 
     return reject(badStatus); 
     } 
     // console.log(response.headers); 
     // console.log(body); 
     const resObj = { 
     headers: response.headers, 
     body: body 
     }; 
     // console.log(`******** ${requestType} *********`); 
     // console.log(resObj); 
     // console.log('----------------------------------'); 
     return resolve(resObj); 
    }); 
    }); 
}; 

module.exports = expObj; 
+1

Dies ist das [Explizite Versprechen Konstruktion Anti-Muster] (https: // stackoverflow.com/questions/23803743/was-ist-die-explizite-versprechen-konstruktion-antipattern-und-wie-do-i-vermeiden-es). Dies ist das erste, was Sie beheben sollten. 'new Promise()' wird nur immer benötigt, wenn Sie eine Callback-basierte API promoten, die Sie nicht sind. In diesem Fall sollten Sie von "request" zu "request-promise" wechseln (https://github.com/request/request-promise). – Tomalak

+1

Das nächste, was Sie beheben sollten, ist Ihre Abhängigkeit von einer äußeren Scope-Variable ('apiCardItem' in diesem Fall), die den asynchronen Zustand enthält. Die Rückgabewerte von Ihren Versprechungshandlern sollten Operationsergebnisse enthalten. – Tomalak

+0

Danke @Tomalak. Ihre Hinweise haben geholfen, das Problem zu lösen. – hyprstack

Antwort

0

Ich schrieb Ihre " TestC ard“-Funktion (controller.js)

//Tests response from API for different cards 
 
const testCard = (cardNum) => { 
 
    return new Promise((resolve, reject) => { 
 
    let apiCardItem = ''; 
 
    const expDate = new Date(); 
 
    const cardObj = { 
 
     cardNum: cardNum, 
 
     expMonth: expDate.getMonth() + 1, 
 
     expYear: expDate.getFullYear() + 2 
 
    }; 
 
    
 
    testRequestToApi('getStripeToken', 200, 299, cardObj) 
 

 
     .then((cardItem) => testRequestToApi('postNewCard', 200, 299, JSON.parse(cardItem.body))) 
 

 
     .then((apiCard) => { 
 
     apiCardItem = apiCard.body; 
 
     try { 
 
      apiCardItem = JSON.parse(apiCardItem); 
 
     } catch(e) { 
 
      console.log(e); 
 
     } 
 
     return testRequestToApi('sampleAddToCart', 200, 299); 
 
     }) 
 

 
     .then(() => testRequestToApi('useFailingStripeCards', 400, 499, apiCardItem.id)) 
 

 
     .then(() => testRequestToApi('deleteCard', 200, 299, apiCardItem.id)) 
 

 
     .then(resolve) 
 

 
     .catch(reject); 
 
    }); 
 
};

Und Ihre "testRequestToApi"(Test-Anfrage-to-api.js)

expObj.testRequestToApi = (requestType, lowerLimit, upperLimit, item) => { 
 
    return new Promise((resolve, reject) => { 
 
    const reqOps = formHeaders[requestType](item); 
 

 
    request(reqOps, (err, response, body) => { 
 
     let badStatus = {}; 
 
     let badRequest = {}; 
 
     let resObj  = {}; 
 

 
     if (err) { 
 
     badRequest = { 
 
      ErrorMessage: err, 
 
      FuncName:  requestType, 
 
      InternalError: true 
 
     }; 
 

 
     reject(badRequest); 
 
     return false; 
 
     } 
 
     
 
     if (!checkStatus.checkRangeStatusCode(response.statusCode, lowerLimit, upperLimit)) { 
 
     console.log(JSON.stringify(body, null, 2)); 
 
     // Set a bad Status error object 
 
     badStatus = { 
 
      StatusCode: response.statusCode, 
 
      ErrorMessage: body, 
 
      FuncName:  requestType, 
 
      InternalError: false 
 
     }; 
 

 
     reject(badStatus); 
 
     return false; 
 
     } 
 

 
     resObj = { 
 
     headers: response.headers, 
 
     body: body 
 
     }; 
 

 
     resolve(resObj); 
 
    }); 
 
    }); 
 
};

Ich denke, das Problem ist, wenn du von einem Versprechen zurückkehrst, bevor eine Entschlossenheit/Ablehnung angerufen wird.

Überprüfen Sie auch, dass Sie in geschachtelten Zusagen die Auflösung/Zurückweisung an .then/catch übergeben können.

+0

Funktioniert immer noch nicht. Gleicher Fehler. ''testAllCards wurde ausgeführt'' ist noch angemeldet, bevor andere Funktionen eingeloggt werden – hyprstack

2

Verstehen, dass new Promise() nur immer benötigt wird, wenn eine Callback-basierte API Promistifizierung, Wechsel zu request-promise und die Rückgabe meiner Versprechen in cli.js mein Problem gelöst. Der Ausführungsablauf wurde auf diese Weise korrekt beibehalten.

Änderungen an den folgenden Dateien sind wie folgt: cli.js

const testAllCards =() => { 
    return controller.testAllCards(config.get('CARD_NUMBERS')) 
    .then((obj) => { 
     console.log('testAllCards has been run'); 
    }) 
    .catch((e) => { 
    console.log(e) 
     console.log('testCards has been run with an error!'); 
     const _err = new ErrHandler(e, eTopicName, eSnsSubject); 
     return _err.handle() 
     .then(() => { 
      console.log('Error has been sent with success to sns'); 
     }) 
     .catch((e) => { 
      console.log('Failed to publish to sns'); 
      console.log(e); 
     }); 
    }); 
}; 

Test-Anfrage-to-api

'use strict'; 

const checkStatus = require('./../utils/status-code-checker'); 
const formHeaders = require('./../utils/form-req-headers'); 
const rqp   = require('request-promise'); 
const expObj = {}; 

//@requestType {string} - defines which headers and function name to use 
//@item {object} - defines item that is being used 
expObj.testRequestToApi = (requestType, lowerLimit, upperLimit, item) => { 
    const reqOps = formHeaders[requestType](item); 
    return rqp(reqOps) 
    .then((response) => { 
     if (!checkStatus.checkRangeStatusCode(response.statusCode, lowerLimit, upperLimit)) { 
     console.log(JSON.stringify(response.body, null, 2)); 
     // Set a bad Status error object 
     return { 
      StatusCode: response.statusCode, 
      ErrorMessage: response.body, 
      FuncName: requestType, 
      InternalError: false 
     }; 
     } 
     // console.log(response.headers); 
     // console.log(response.body); 
     const resObj = { 
     headers: response.headers, 
     body: response.body, 
     previousItem: item 
     }; 
     // console.log(`******** ${requestType} *********`); 
     // console.log(resObj); 
     // console.log('----------------------------------'); 
     return resObj; 
    }) 
    .catch((e) => { 
     return { 
     ErrorMessage: e, 
     FuncName: requestType, 
     InternalError: true 
     }; 
    }); 
}; 

module.exports = expObj; 

controller.js

//Tests response from API for different cards 
Controller.testCard = (cardNum) => { 
    const expMonth = new Date().getMonth() + 1; 
    const expYear = new Date().getFullYear() + 2; 
    const cardObj = { 
    cardNum: cardNum, 
    expMonth: expMonth, 
    expYear: expYear 
    }; 
    let apiCardItem = ''; 
    return testRequestToApi('getStripeToken', 200, 299, cardObj) 
    .then((cardItem) => { 
     return testRequestToApi('postNewCard', 200, 299, JSON.parse(cardItem.body)); 
    }) 
    .then((apiCard) => { 
     apiCardItem = apiCard.body; 
     try { 
     apiCardItem = JSON.parse(apiCardItem); 
     } catch(e) { 
     console.log('Already a JSON object -----> Moving on'); 
     } 
     return testRequestToApi('sampleAddToCart', 200, 299); 
    }) 
    .then(() => testRequestToApi('useFailingStripeCards', 400, 499, apiCardItem.id)) 
    .then(() => testRequestToApi('deleteCard', 200, 299, apiCardItem.id)); 
}; 

//Loops through the card numbers and runs the test command against them 
Controller.testAllCards = (cardsArray) => { 
    return Promise.all(cardsArray.map((cardNum) => { 
    return Controller.testCard(cardNum); 
    })); 
}; 

module.exports = Controller; 
+1

Gute Antwort. Ich hatte praktisch den gleichen Code parat, aber verlor etwas in Details, die philosophischer Natur sind, also dachte ich mir, dass das Aufzeigen der zwei Hauptprobleme, die ich gesehen habe, ausreichen würde, um es herauszufinden. :) – Tomalak

Verwandte Themen