2017-06-14 56 views
2

我有一系列的承諾,我已鏈接在testCard。此方法需要一個stripe卡號,從條帶獲取令牌,然後與試圖使用該卡執行購買的第三方API進行通話。 我需要運行testCard循環卡號的數組。要做到這一點,我有一個controller對象與方法testAllCards它採用數組數組。該數組存儲在配置文件中。Nodejs承諾所有不按預期運行

然後我通過命令行運行代碼node cli.js testAllCards

但是,當我運行它,我得到testAllCards has been run之前所有的大多數承諾已經解決。 我很明顯錯過了這裏的東西,但似乎無法弄清楚它是什麼。

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; 

測試請求 - 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

這是[顯式承諾構造反模式](https:// stackoverflow。COM /問題/ 23803743 /什麼,是最明確的,承諾建設,反模式和如何-DO-I-避免-IT)。這是你應該修復的第一件事。當你承諾一個基於回調的API時,'new Promise()'是唯一必需的,你不是。同樣,你應該從'request'切換到['request-promise'](https://github.com/request/request-promise)。 – Tomalak

+1

您應該修復的下一件事是您對外部變量變量(在本例中爲'apiCardItem')的依賴以包含異步狀態。您的承諾處理程序的返回值應包含操作結果。 – Tomalak

+0

謝謝@Tomalak。你的指針幫助解決了這個問題。 – hyprstack

回答

0

我改寫了你的「 TESTC ARD」功能(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); 
 
    }); 
 
};

而你的 「testRequestToApi」(測試請求 - 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); 
 
    }); 
 
    }); 
 
};

我認爲問題在於,在解決/拒絕被調用之前,您從承諾中回報。

還要檢查在嵌套承諾中,爲了簡潔,您可以將解析/拒絕傳遞給.then/catch。

+0

仍然無法使用。同樣的問題。 ''testAllCards已經運行''仍然記錄在其他功能的日誌之前 – hyprstack

2

瞭解promisifying當一個基於回調的API,改爲request-promise並返回我的諾言在cli.js解決了我的問題是new Promise()只用以往任何時候都需要。以這種方式正確維護執行流程。

更改到下面的文件是如下: 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); 
     }); 
    }); 
}; 

測試請求到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

好的答案。我已經準備好了幾乎相同的代碼,但是在具有更多哲學性質的細節方面有些迷失,所以我想指出我看到的兩個主要問題足以讓你弄清楚。 :) – Tomalak