【问题标题】:How to solve promise issue?如何解决承诺问题?
【发布时间】:2016-11-21 15:54:29
【问题描述】:

我是 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 时,我可以看到数组实际上已被填充,但该代码在 promise 被解决后运行。 简而言之:如何绑定餐厅中的 resolve 承诺在登录功能完成之前不发送数据?

换句话说,我如何从登录后功能中获取填充的数组?

【问题讨论】:

  • 我没有发现任何问题...也许您遗漏了一些代码或什么?如果data 包含您的数组,那么一切都很好。
  • httpafterlogin 需要与另一个相同的承诺设置。
  • 但是我尝试了 Kevin B 但它不起作用
  • 我没有看到你在你的问题中尝试过的地方,所以我无法评论你是如何错误地尝试的。
  • 由于你是新的 promises,你会想看看我的rules of thumb。您违反了其中的多个。

标签: javascript node.js functional-programming promise


【解决方案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);
    });
}

然后像rsp建议的那样使用.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 完成之前不会被调用

【讨论】:

  • 第一句话是,但要避免Promise constructor antipattern!
  • 这样更好吗?如果不是,我会很感激解释,我想学习,但搜索结果似乎主要涉及已经返回承诺的函数的多余包装(而不是本例中的回调样式函数)
  • 我相信这修复了损坏的错误链接(我理解的反模式的主要负面因素)
  • 谢谢,是的。你可能想对httplogin 中的new Promise 做类似的事情,回调中的所有代码都应该放在一个单独的then 回调中(所以你只在不安全的nodeback 中执行if (error) reject(error) else resolve(response))。特别是因为httpAfterLogin 也是异步的,也应该重写以返回一个承诺。
  • 啊,没注意到afterhttplogin 也是异步的。这个编辑怎么样?
【解决方案2】:

在整个代码中使用 Promise - 您可以使用 request-promise 包代替 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;
    });
}

【讨论】:

  • 你忘了return承诺无处不在
  • .then(function (data) { return data; }).catch(function(error){ throw error; }); 之类的东西毫无意义——没有它们也一样——应该简单地省略。特别是如果您想要可读和可维护的代码。
【解决方案3】:

如果您不希望在登录完成之前解决承诺,那么您将不得不让您的 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);
});

使用 Promise 有更多的方法,但这是最简单的方法。

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

【讨论】:

  • 其实这就是问题所在,我可以在 Promise 中添加 Promise 吗?我的意思是如何包装我的 http 函数?如果你能告诉我我是如何尝试 bkz 的,你会非常好,但它对我不起作用
猜你喜欢
  • 2017-05-08
  • 2020-09-07
  • 2017-06-04
  • 1970-01-01
  • 2015-06-24
  • 1970-01-01
  • 2016-12-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多