js promises 的问题(bluebird)

Trouble with js promises (bluebird)

我正在尝试从列表中的 MailChimp 中创建合并字段(如果它们尚不存在)。如果它们不存在,我希望将它们推送到承诺列表中,我在其中使用 promises.all 来确保已添加所有必要的列表项。

虽然这不起作用。我究竟做错了什么?

var productDict = []

var getMergeNumPromise = new Promise( 
    function(resolve, reject) {
        // call to mailchimp to get the number of merge fields
        rp({
            uri: MAILCHIMP_MERGEFIELDS_URI, 
            qs:{count:1}, 
            json:true, 
            headers:MAILCHIMP_HEADER
        })
        .then(function( mergeFieldList ) {
            console.log("total items: " + mergeFieldList.total_items)
            resolve(mergeFieldList.total_items)
        })
        .catch(function(err) {
            console.log("error getting merge field count: " + err)
            reject(err)
        })
    }
)

var getMergeFieldsPromise = new Promise( 
    function( resolve, reject ) {
        getMergeNumPromise.then(function( total, err ){
            //gets just the name and tag for all merge fields in the list
            rp({
                uri: MAILCHIMP_MERGEFIELDS_URI, 
                qs:{
                    count: total,
                    fields: "merge_fields.tag,merge_fields.name"
                },
                headers: MAILCHIMP_HEADER
            })
            .then(function( fullFieldList ) {
                console.log("FULL FIELD BODY" + fullFieldList)
                var body = JSON.parse(fullFieldList)
                resolve(body.merge_fields)
            })
            .catch(function(err){
                console.log("error getting fields: " + err)
                reject(err)
            })
        })
    }
)

function addMergeField (prodName , dictPos) {
    return new Promise (
        function(resolve, reject) {
            fieldBody = { name : prodName , type : "number"}

            //post request to make the new merge field
            rp({
                method: "POST", 
                uri: MAILCHIMP_MERGEFIELDS_URI, 
                json: true, 
                headers: MAILCHIMP_HEADER, 
                body: fieldBody
            })
            .then(function(body) {
                //update product dictionary
                productDict[dictPos] = {tag : body.tag, name : body.name}
                console.log("MERGE FIELD RESPONSE " + JSON.stringify(body))
                resolve(body)
            })
           .catch(function(err) {
                console.log("error creating merge field for product id: " + err)
                reject(err)
            })
        }
    )
}

var updateMergeFields = getMergeFieldsPromise.then( 
    function( mergeFieldList ) {
        // resolved ids keeps track of ids that have already been added
        var resolvedIDS = {}
        //holds result of find to look for product ids
        var foundMCMatch
        // holds productIDS[i]
        var product
        //console.log("merge field list" + JSON.stringify(mergeFieldList))

        for(var i = 0; i < productIDS.length; i++) {
            console.log("checking if product id " + productIDS[i] + "exists")
            product = productIDS[i]
            // tries to find a match to see if fields are already in mailchimp
            foundMCMATCH = mergeFieldList.find(x => x.name == product)

            if(foundMCMATCH) {
                console.log("foundMCMATCH" + JSON.stringify(foundMCMATCH))

                //updates product dict with matching tag/name from mailchimp
                productDict[i] = {
                    tag : foundMCMATCH.tag, 
                    name : foundMCMATCH.name
                }
                //console.log("PRODUCT DICT " + JSON.stringify(productDict))
            }

            //if field isn't on mailchimp
            else if (!resolvedIDS[product])
            {
                resolvedIDS[product] = true

                // adds product id as merge field becasue it doesn't exist
                allProductIDPromises.push(
                    addMergeField(product,i)
                )
            }
        }
    }
)

allProductIDPromises.push( getMergeFieldsPromise, getMergeNumPromise, updateMergeFields ) 
Promise.all(allProductIDPromises) 
.then(function() { 
    //function here that's running out of order
}

注意:我正在使用请求承诺来发出我的 post 请求,因此它们已经被承诺。

getMergeFieldsPromisethen 回调没有 returning 任何东西,所以一旦 getMergeFieldsPromise 被解决,它就不会等待 addMergeField 承诺,而是立即解决(undefined 作为承诺值)。

要解决这个问题,请在 then 回调中将 allProductIDPromises 设为局部变量并对其调用 Promise.all,然后 return 在那里:

var updateMergeFields = getMergeFieldsPromise.then( 
    function( mergeFieldList ) {
        // **** make the array of promises local to this function
        var allProductIDPromises = [];
        // resolved ids keeps track of ids that have already been added
        var resolvedIDS = {}
        //holds result of find to look for product ids
        var foundMCMatch
        // holds productIDS[i]
        var product
        //console.log("merge field list" + JSON.stringify(mergeFieldList))

        for(var i = 0; i < productIDS.length; i++) {
            console.log("checking if product id " + productIDS[i] + "exists")
            product = productIDS[i]
            // tries to find a match to see if fields are already in mailchimp
            foundMCMATCH = mergeFieldList.find(x => x.name == product)

            if(foundMCMATCH) {
                console.log("foundMCMATCH" + JSON.stringify(foundMCMATCH))

                //updates product dict with matching tag/name from mailchimp
                productDict[i] = {
                    tag : foundMCMATCH.tag, 
                    name : foundMCMATCH.name
                }
                //console.log("PRODUCT DICT " + JSON.stringify(productDict))
            }

            //if field isn't on mailchimp
            else if (!resolvedIDS[product])
            {
                resolvedIDS[product] = true

                // adds product id as merge field becasue it doesn't exist
                allProductIDPromises.push(
                    addMergeField(product,i)
                )
            }
        }
        // **** call Promise.all here, and return it
        return Promise.all(allProductIDPromises);
    }
)

然后,你应该删除这个:

allProductIDPromises.push( ... )

...并且由于您的主要三个承诺已经与 then 链接在一起,您只需要对最后一个承诺执行 then

updateMergeFields.then(function(addedMergeFields) { 
    // ... all is ready now.
}

最后,阅读您多次使用的 Promise constructor anti-pattern:您不应该使用 new Promise,而实际上您可以 return 承诺(例如 return rp()).