如何解决承诺问题?

时间:2016-11-21 15:54:29

标签: javascript node.js functional-programming promise

我是Promise概念的新手,并试图包围我,但现在我在这里感到困惑

const request = require("request");
const cheerio = require("cheerio");
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
var url = require("url");


module.exports = {

    resturant: resturant,

};


var resturanttables = [];

function resturant(url, day) {

    return new Promise(function(resolve, reject) {
        request(url, function(error, response, html) {

            if (error) {
                return reject(error);

            } else if (response.statusCode !== 200) {

                return reject("Something is wrong! CINEMA")

            }
            httplogin("zeke", "coys", url, day);
            console.log(resturanttables, "i am here");

            resolve(resturanttables);

        });



    });
}

function httpafterlogin(url, cookie, day) {

    request.get({
            headers: {
                'content-type': 'text/html',
                'Cookie': cookie
            },
            url: url,
        },

        function(error, response, body) {



            console.log(day)
            var $ = cheerio.load(body);

            if (day === "Friday") {
                $(".WordSection2 p  span ").each(function(li) {
                    //  console.log(day, $(this).text())
                    resturanttables.push($(this).text());

                    console.log(resturanttables, "nside");
                });

            } else if (day === "Saturday") {
                $(".WordSection4 p span").each(function(li) {

                    resturanttables.push($(this).text())
                });

            } else {
                $(".WordSection6 p span").each(function(li) {

                    resturanttables.push($(this).text())


                });

            }

        });

}

function httplogin(username, password, urls, day) {

    request.post({
        headers: {
            'content-type': 'application/x-www-form-urlencoded'

        },
        url: urls,
        form: {
            "username": username,
            "password": password


        }
    }, function(error, response, body) {
        var cookie = response.caseless.dict['set-cookie'][0];
        var location = response;

        console.log(response.statusCode);
        cookie = cookie.substring(0, cookie.indexOf(';'));

        // httpafterlogin('http://vhost3.lnu.se:20080/dinner/'+response.headers.location, cookie);
        var newurls = url.resolve(urls, response.headers.location)
        httpafterlogin(newurls, cookie, day);

        // console.log(response.headers, "jdjdjjdjdjjdjdjdjjdjjdjdj")

    });

}

然后我调用函数

loadPage.resturant("http://vhost3.lnu.se:20080/dinner/login", "Friday").then(function(data) {
    console.log(data, "did it work now ")
})

问题是它返回空数组。但是当我尝试在afterlogin函数中检查和console.log时,我可以看到该数组实际已被填充,但该代码在承诺解决后运行。 简而言之:如何在餐厅承诺中约束解决方案,直到登录功能完成后才发送数据?

换句话说,如何从填充后的数组中获取来自afterlogin功能的信息?

3 个答案:

答案 0 :(得分:1)

重写httploginhttpafterlogin以返回承诺:

function httpafterlogin (url, cookie, day) {
    return new Promise(function (resolve, reject) {
        request.get({
            headers: {
                'content-type': 'text/html',
                'Cookie': cookie
            },
            url: url
        }, function (error, response, body) {
            if (error) {
                reject(error);
            } else {
                resolve(body);
            }
        });
    }).then(function (body) {
        console.log(day);
        var $ = cheerio.load(body);

        if (day === "Friday") {
            $(".WordSection2 p span").each(function (li) {
                //  console.log(day, $(this).text());
                resturanttables.push($(this).text());
                console.log(resturanttables, "nside");
            });
        } else if (day === "Saturday") {
            $(".WordSection4 p span").each(function (li) {
                resturanttables.push($(this).text());
            });
        } else {
            $(".WordSection6 p span").each(function(li) {
                resturanttables.push($(this).text());
            });
        }
    });
}


function httplogin(username, password, urls, day) {
    return new Promise(function (resolve, reject) {
        request.post({
            headers: {
                'content-type': 'application/x-www-form-urlencoded'
            },
            url: urls,
            form: {
                "username": username,
                "password": password
            }
        }, function(error, response, body) {
            if (error) {
                reject(error);
            } else {
                resolve(response);
            }
        });
    }).then(function (response) {

        var cookie = response.caseless.dict['set-cookie'][0];
        var location = response;

        console.log(response.statusCode);
        cookie = cookie.substring(0, cookie.indexOf(';'));

        var newurls = url.resolve(urls, response.headers.location)
        return httpafterlogin(newurls, cookie, day);
    });
}

然后像{rs}建议使用.then

function resturant(url, day) {

    return new Promise(function(resolve, reject) {
        request(url, function(error, response, html) {
            if (error) {
                return reject(error);
            } else {
                resolve(response);
            }
        })
    }).then(function (response) {
        if (response.statusCode !== 200) {
            throw new Error("Something is wrong! CINEMA");     
        }
        return httplogin("zeke", "coys", url, day)
    }).then(function () {
        console.log(resturanttables, "i am here");
        return resturanttables;
    });
 }

这样,在resolve(restautanttables)完成

之前,不会调用包含httplogin的块

答案 1 :(得分:0)

如果您不希望在登录完成之前解决承诺,那么您必须让httplogin函数接受回调并按照以下方式运行:

httplogin("zeke", "coys", url, day, function (err) {
  if (err) {
    reject(err);
  } else {
    resolve(resturanttables);
  }
});

或让它返回一个承诺并运行它,例如:

httplogin("zeke", "coys", url, day).then(function () {
  resolve(resturanttables);
}).catch(function (err) {
  reject(err);
});

有很多方法可以通过promises来实现,但这是最简单的方法。

无论哪种方式,你必须通过调用它作为参数的回调或解析它返回的承诺来使你的httplogin函数信号完成。

答案 2 :(得分:0)

在整个代码中使用promises - 您可以使用request-promise包代替请求包来简化代码。所有请求都成为承诺,代码更易于阅读和维护。

const rp = require("request-promise");
const cheerio = require("cheerio");
const url = require("url");

function resturant(url, day) {
  rp(url)
    .then(function(){
      // URL returned a 200 response
      // so attempt to perform login
      httplogin("zeke", "coys", url, day)
        .then(function (data) {
          // Promise is resolved here
          return data;
        });
    })
    .catch(function(error){
      // just throwing the error
      throw error;
    });
}

function httplogin(username, password, urls, day) {
  var options = {
    headers: {
      "content-type": "application/x-www-form-urlencoded"
    },
    uri: urls,
    form: {
      username: username,
      password: password
    },
    method: "POST",
    resolveWithFullResponse: true
  };
  rp(options)
    .then(function (response) {
      // POST succeeded
      // grab the cookie
      var cookie = response.caseless.dict['set-cookie'][0]
                           .substring(0, cookie.indexOf(';'));
      // get new url string
      var newurls = url.resolve(urls, response.headers.location);

      httpafterlogin(newurls, cookie, day)
        .then(function (tables) {
          return tables;
        })
        .catch(function (error) {
         // just throwing the error
         throw error;
        });

    })
    .catch(function (error) {
      // Login failure
      // just throwing the error
      throw error;
    });
}

function httpafterlogin(url, cookie, day) {
  var options = {
    headers: {
      "content-type": "text/html",
      "Cookie": cookie
    },
    uri: url,
    transform: function (body) {
      return cheerio.load(body);
    }
  };
  rp(options)
    .then(function ($) {
      // body has been transformed and
      // can now be processed with jQuery

      // initialise the tables array
      var tables = [];

      // DRY code
      // set default selector
      var selector = ".WordSection6 p span";
      // change the selector for Friday/Saturday
      if (day === "Friday") {
        selector = ".WordSection2 p  span ";
      } else if (day === "Saturday") {
        selector = ".WordSection4 p span";
      }
      // process the selected section
      $( selector ).each(function(li) {
        tables.push($(this).text())
      });

      // crawling complete
      return tables;
    })
    .catch(function (error) {
      // Crawling failure
      // just throwing the error
      throw error;
    });
}