如何等待值被添加到数组?

How to await values being added to array?

我有一个项目,我正在使用 Request-Promise 和 Cheerio 解析快餐菜单,然后根据用户的要求返回“订单”。但是,我在输出存储为数组的“订单”时遇到了一些问题。

var rp = require('request-promise');
var cheerio = require('cheerio');
var tempMenu = [];
var order = [];

function getItem(item) {

    var itemUrl = baseURL + '/' + item

    var itemMenu = {
        uri: itemUrl,
        transform: function (body) {
            return cheerio.load(body);
        }
    };

    rp(itemMenu)
        .then(function ($) {          
            //.class #id tag
            $(".product-card .product-name a").each(function () {
                tempMenu.push($(this).text());
                order.push(tempMenu[Math.floor(Math.random() * tempMenu.length)]);
                
            });
            console.log(order)
        })

        .catch(function (err) {
        }); 
}

getItem('drinks')
console.log(order)

目前,输出是:

[]
[
 'drink1',
 'drink2',
 'drink3'
]

如果我将代码更改为以下内容:

  rp(itemMenu)
        .then(function ($) {          
            //.class #id tag
            $(".product-card .product-name a").each(function () {
                tempMenu.push($(this).text());
                order.push(tempMenu[Math.floor(Math.random() * tempMenu.length)]);
                
            });
            console.log(1)
        })

        .catch(function (err) {
        }); 
}

getItem('drinks')
console.log(2)

日志是

2
1

所以我知道我的问题是当我尝试输出“order”数组时它没有被填充,因为它首先被记录,我的问题是我如何等待数组被填充,然后输出它?

之所以会这样,是因为then cb函数进入了回调队列。 您应该将它们都包装在一个异步函数中,并在您要等待的部分使用 await。

这应该可以解决您的问题。

您的 getItem 函数应该 return 一个 Promise and then you can either use the Promise.prototype.then() method on it or the await 关键字以确保您在尝试处理结果之前等待结果。

这是一个简单的示例,其中包含一些伪造的 rp 函数和数据:

// Fake:
const rp = (item) => {
  console.log(`Fetching ${ item }...`);
  
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(Math.random());
    }, 1000 + Math.random() * 2000)
  });
}

function getItem(item) {
  const order = [];
  
  // This `getItem` function returns a Promise...
  return rp(item).then((randomNumber) => {          
    for (let i = 0; i < 10; ++i) {
      order.push(`${ item } ${ randomNumber + i }`);
    }
    
    // ...and when this Promise resolves, it will return the `order`
    // array with the right values in it:
    return order;
  });
}

getItem('Drinks').then(order => console.log(order));

console.log('This is executed after calling getItem, but we ware still waiting for the Promise to resolve...');
.as-console-wrapper {
  max-height: none !important;
}

替代async/await

// Fake:
const rp = (item) => {
  console.log(`Fetching ${ item }...`);
  
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(Math.random());
    }, 1000 + Math.random() * 2000)
  });
}

function getItem(item) {
  const order = [];
  
  // This `getItem` function returns a Promise...
  return rp(item).then((randomNumber) => {          
    for (let i = 0; i < 10; ++i) {
      order.push(`${ item } ${ randomNumber + i }`);
    }
    
    // ...and when this Promise resolves, it will return the `order`
    // array with the right values in it:
    return order;
  });
}

// You can't use `await` outside an `async` function, so we define this first...:
async function loadDataWithAwait() {
  const order = await getItem('Food');

  console.log('This won\'t be executed until getItem\'s Promise is resolved:');
  console.log(order);
}

// ...and now call it:
loadDataWithAwait();
.as-console-wrapper {
  max-height: none !important;
}