在退出进程之前等待承诺

发布于 2025-01-20 14:14:22 字数 1870 浏览 3 评论 0原文

我正在尝试运行一个nodejs代码,该代码从数组中读取一些数据字段,请使用它们进行数据库查询以检查数据是否在将数据插入到相应的表格中。

我的nodejs代码将从PHP脚本调用,因此我需要知道它何时结束,这就是为什么我需要在某个地方添加process.exit(0)。我的问题是,如果添加它,脚本将终止,我的承诺永远没有时间发送结果。

这是我的代码:

var bar = new Promise((resolve, reject) => {
        result.forEach((row, index, array) => {
            var escaped = _.map(row, mysql.escape);
            var checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = " + escaped[0] + " AND field2 = " + escaped[1] + " AND field3 = " + escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " + escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
            conn.query(checkQuery, function (err, res) {
                if (err) {
                    console.log("Error checking row for duplicate");
                    console.log(checkQuery);
                    process.exit(1);
                } else {
                    if (res[0].found == 0) {
                        var query = " (";
                        var escaped = _.map(row, mysql.escape);
                        var csv = escaped.join(',');
                        query += csv;
                        query += ")";
                        query += row !== _.last(result) ? ',' : ';';
                        console.log(query);//This will change to inserting the data to the table
                    }else{
                        console.log("Duplicate found!");
                    }
                }
            });
            if (index === array.length -1) resolve();
        });
    });

    bar.then(() => {
        console.log('All done!');
        process.exit(0);
    });

如果我删除process.exit(0);我看到“全部完成” 首先,然后console.log(query)>结果。 如果添加它,脚本将终止,我看到“全部完成”

请问有更好的方法来完成这项任务吗?

谢谢。

I'm trying to run a NodeJS code that reads some data fields from an array, use them to do a database query to check if the data is duplicate before inserting them into the corresponding table.

My NodeJS code will be called from a PHP script so I need to know when it ends this is why I need to add process.exit(0) somewhere. The problem I have is that if I add it, the script is terminated and my promise never gets the time to send back the result.

Here is my code:

var bar = new Promise((resolve, reject) => {
        result.forEach((row, index, array) => {
            var escaped = _.map(row, mysql.escape);
            var checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = " + escaped[0] + " AND field2 = " + escaped[1] + " AND field3 = " + escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " + escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
            conn.query(checkQuery, function (err, res) {
                if (err) {
                    console.log("Error checking row for duplicate");
                    console.log(checkQuery);
                    process.exit(1);
                } else {
                    if (res[0].found == 0) {
                        var query = " (";
                        var escaped = _.map(row, mysql.escape);
                        var csv = escaped.join(',');
                        query += csv;
                        query += ")";
                        query += row !== _.last(result) ? ',' : ';';
                        console.log(query);//This will change to inserting the data to the table
                    }else{
                        console.log("Duplicate found!");
                    }
                }
            });
            if (index === array.length -1) resolve();
        });
    });

    bar.then(() => {
        console.log('All done!');
        process.exit(0);
    });

If I remove process.exit(0); I see "All done" first then console.log(query) result.
If I add it, the script is terminated and I see "All done" only.

Is there a better approach to do this task please?

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花海 2025-01-27 14:14:23

这是一种在应用程序退出之前等待承诺的方法。

class Waiter {
  private timeout: any
  constructor() {
    this.waitLoop()
  }
  private waitLoop():void {
    this.timeout = setTimeout(() => { this.waitLoop() }, 100 * 1000)
  }
  okToQuit():void {
    clearTimeout(this.timeout)
  }
}

// Your app.

const appPromise:Promise<any> = ...

const w = new Waiter()
appPromise.finally(() => {
  console.log("Quitting")
  w.okToQuit()
})

Here is a way to wait for a promise before the application exits.

class Waiter {
  private timeout: any
  constructor() {
    this.waitLoop()
  }
  private waitLoop():void {
    this.timeout = setTimeout(() => { this.waitLoop() }, 100 * 1000)
  }
  okToQuit():void {
    clearTimeout(this.timeout)
  }
}

// Your app.

const appPromise:Promise<any> = ...

const w = new Waiter()
appPromise.finally(() => {
  console.log("Quitting")
  w.okToQuit()
})
桃酥萝莉 2025-01-27 14:14:23

如果您对所有单独的异步操作使用 Promise,而不是尝试跟踪使用普通回调的异步操作,则在循环中运行多个异步操作并跟踪一切完成时间会变得非常非常容易。

你没有确切地说你的数据库是什么,但如果它是 mysql,那么就有一个 mysql2/promise 驱动程序本身支持承诺,这将是我建议切换到该驱动程序。然后你可以直接使用从.query()返回的promise。但是,在没有有关特定数据库驱动程序的信息的情况下,我展示了如何手动 promisify .query()

然后,循环代码可以使用 for 循环和 await 对数据库调用进行排序,以便很容易知道它们何时完成。

const { promisify } = require('util');

async function someFunc() {
    // other code here

    // promisify conn.query (or use promise interface directly from the database)
    conn.queryP = promisify(conn.query);

    try {
        for (const row of result) {
            const escaped = _.map(row, mysql.escape);
            const checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = " + escaped[0] + " AND field2 = " +
                escaped[1] + " AND field3 = " + escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " +
                escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
            let res = await con.queryP(checkQuery);
            if (res[0].found == 0) {
                const csv = _.map(row, mysql.escape).join(',');
                const terminator = row !== _.last(result) ? ',' : ';';
                const query = " (" + csv + ")" + terminator;
                console.log(query); //This will change to inserting the data to the table
            } else {
                console.log("Duplicate found!");
            }

        }
    } catch (e) {
        console.log("Error checking row for duplicate: ", checkQuery);
        console.log(e);
        process.exit(1);
    }
    console.log('All done!');
    process.exit(0);
}

该代码似乎试图在循环内构建一个查询,其中循环的每次迭代都会添加到下一次迭代(这就是 _.last(result) ? ',' : ';'; 无论如何看起来都像)。如果是这种情况,则必须将查询变量移到循环之外,以便它可以从循环的一次迭代构建到下一次迭代。但是,您没有显示您真正想对该查询执行什么操作,因此您只能自己完成该部分。

Running multiple asynchronous operations in a loop and tracking when everything is done is just way, way, way easier if you use promises for all the individual asynchronous operation rather than trying to track asynchronous operations that use plain callbacks.

You don't say exactly what your database is, but if it's mysql, then there is a mysql2/promise driver that natively supports promises and that would be my recommendation to switch to that. Then you can directly use a promise returned from .query(). But, without the info about your specific database driver, I've shown how to manually promisify .query().

Then, the looping code can use a for loop and await to sequence the database calls so it's easy to know when they are all complete.

const { promisify } = require('util');

async function someFunc() {
    // other code here

    // promisify conn.query (or use promise interface directly from the database)
    conn.queryP = promisify(conn.query);

    try {
        for (const row of result) {
            const escaped = _.map(row, mysql.escape);
            const checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = " + escaped[0] + " AND field2 = " +
                escaped[1] + " AND field3 = " + escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " +
                escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
            let res = await con.queryP(checkQuery);
            if (res[0].found == 0) {
                const csv = _.map(row, mysql.escape).join(',');
                const terminator = row !== _.last(result) ? ',' : ';';
                const query = " (" + csv + ")" + terminator;
                console.log(query); //This will change to inserting the data to the table
            } else {
                console.log("Duplicate found!");
            }

        }
    } catch (e) {
        console.log("Error checking row for duplicate: ", checkQuery);
        console.log(e);
        process.exit(1);
    }
    console.log('All done!');
    process.exit(0);
}

The code appears to be trying to build a query inside the loop where each iteration of the loop will add-on to the next (that's what _.last(result) ? ',' : ';'; look like anyway). If that's the case, then the query variable has to be moved outside the loop so it can build from one iteration of the loop to the next. But, you don't show what you're really trying to do with that query so you're on your own for that part.

夜血缘 2025-01-27 14:14:23

您可以决定将有多少诺言在手动之前出现,然后在解决方案时对它们进行计数,然后

在此示例中退出相同的原则,但它具有回调功能而不是承诺。为了承诺,您将从.then()或.finally()调用计数函数,并且计数函数将决定是否该是

从JavaScript服务器退出Mongoose示例的时候:

let g_DB = null;

//init mongoose
const mongoose = require("mongoose");
const connectionParams = {
  useNewUrlParser: true,
  useUnifiedTopology: true,
};
const connStr1 = "mongodb+srv://XX:[email protected]/XX? 
    retryWrites=true&w=majority";
mongoose.set("strictQuery", false);
mongoose.connect(connStr1, connectionParams)
    .then(handleConnection())
    .catch((err) => console.log("Error:", err));
//end script

//handleConnection - start on successful response from mongoose connection
function handleConnection(msg) {
  console.log("mongoose has connected to Mongo Atlas successfully");

  g_DB = mongoose.connection;
  g_DB.once("open", function () {
    console.log(
      "mongoose has connected to Mongo Atlas Cluster using database XX"
    );
    doTest();
  });
}

//---------------------------------------------------
function doTest() {
  console.log("test-05: create 500 books");

  //---- MODEL ----
  const _schema = new mongoose.Schema({
    name: String,
    price: Number,
    quantity: Number,
  });

  //g_DB is a mongoose connection set earlier in the script
  const _model = g_DB.model("book_schema", _schema, "bookstore");

  let loopcount = 500;
  let waitcount = loopcount;
  for (let i = 0; i < loopcount; i++) {
    _m = new _model({
      name: `WHY MAKE 500 BOOKS ${new Date().toISOString()}`,
      price: 200,
      quantity: 2000,
    });

    _m.save((e, x) => {
      if (e) return console.error(e);
      console.log(x, `waitcount: ${--waitcount}`);
      if (!waitcount) doExit();
    });
  }
}

//--
function doExit() {
  console.log("exit from server");
  process.exit();
}

you decide how many promises will go out before hand and then count them as they resolve, then exit

in this example the same principle is applied but it has callback functions instead of promises. For promises you would call a count function from the .then() or .finally(), and the count function will decide whether it is time to exit

mongoose example from a javascript server:

let g_DB = null;

//init mongoose
const mongoose = require("mongoose");
const connectionParams = {
  useNewUrlParser: true,
  useUnifiedTopology: true,
};
const connStr1 = "mongodb+srv://XX:[email protected]/XX? 
    retryWrites=true&w=majority";
mongoose.set("strictQuery", false);
mongoose.connect(connStr1, connectionParams)
    .then(handleConnection())
    .catch((err) => console.log("Error:", err));
//end script

//handleConnection - start on successful response from mongoose connection
function handleConnection(msg) {
  console.log("mongoose has connected to Mongo Atlas successfully");

  g_DB = mongoose.connection;
  g_DB.once("open", function () {
    console.log(
      "mongoose has connected to Mongo Atlas Cluster using database XX"
    );
    doTest();
  });
}

//---------------------------------------------------
function doTest() {
  console.log("test-05: create 500 books");

  //---- MODEL ----
  const _schema = new mongoose.Schema({
    name: String,
    price: Number,
    quantity: Number,
  });

  //g_DB is a mongoose connection set earlier in the script
  const _model = g_DB.model("book_schema", _schema, "bookstore");

  let loopcount = 500;
  let waitcount = loopcount;
  for (let i = 0; i < loopcount; i++) {
    _m = new _model({
      name: `WHY MAKE 500 BOOKS ${new Date().toISOString()}`,
      price: 200,
      quantity: 2000,
    });

    _m.save((e, x) => {
      if (e) return console.error(e);
      console.log(x, `waitcount: ${--waitcount}`);
      if (!waitcount) doExit();
    });
  }
}

//--
function doExit() {
  console.log("exit from server");
  process.exit();
}
衣神在巴黎 2025-01-27 14:14:23

使用 Reject/Resolve 来管理 Nodejs 中的 Promise

当您的任务满足您的请求时,使用resolve()发送结果;如果失败则使用reject();

在您的情况下,您没有正确管理承诺,这就是它异步运行的原因,最好使用以下方式并获得正确的返回。

var bar = new Promise((resolve, reject) => {
    return result.forEach((row, index, array) => {
        var escaped = _.map(row, mysql.escape);
        var checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = " + escaped[0] + " AND field2 = " + escaped[1] + " AND field3 = " + escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " + escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
        return conn.query(checkQuery, function (err, res) {
            if (err) {
                console.log("Error checking row for duplicate");
                console.log(checkQuery);
                return reject(err);
            } else {
                if (res[0].found == 0) {
                    var query = " (";
                    var escaped = _.map(row, mysql.escape);
                    var csv = escaped.join(',');
                    query += csv;
                    query += ")";
                    query += row !== _.last(result) ? ',' : ';';
                    console.log(query);//This will change to inserting the data to the table
                    return resolve(query)
                } else {
                    console.log("Duplicate found!");
                    return reject('Duplicate Found');
                }
            }
        });
    });
});

bar.then((data) => {
    console.log('All done!');
});

在上面的代码中,我返回查询+解析/拒绝,因此以更同步的方式运行会更好。
return conn.query(checkQuery, function (err, res) {

另外,在处理这个承诺时,我正在使用 .then((data) 处理,这样我就可以处理该解析 注意:如果您拒绝任何 Promise,则该 Promise 在上面

bar.then((data) => {
    console.log('All done!');
});

的 .then 块中将不可用,您将在 catch 块中找到此拒绝,因此代码将按以下方式更改。

bar.then((data) => {
    console.log('All done!');
}).catch(err=>{
    console.log(err);
});

Use Reject/Resolve to manage promise in Nodejs

When your task fulfils your request send result with resolve(); and if its failing use reject();

In your case you are not managing promise properly that's why it's running asynchronously, better to use following way with the proper returns.

var bar = new Promise((resolve, reject) => {
    return result.forEach((row, index, array) => {
        var escaped = _.map(row, mysql.escape);
        var checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = " + escaped[0] + " AND field2 = " + escaped[1] + " AND field3 = " + escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " + escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
        return conn.query(checkQuery, function (err, res) {
            if (err) {
                console.log("Error checking row for duplicate");
                console.log(checkQuery);
                return reject(err);
            } else {
                if (res[0].found == 0) {
                    var query = " (";
                    var escaped = _.map(row, mysql.escape);
                    var csv = escaped.join(',');
                    query += csv;
                    query += ")";
                    query += row !== _.last(result) ? ',' : ';';
                    console.log(query);//This will change to inserting the data to the table
                    return resolve(query)
                } else {
                    console.log("Duplicate found!");
                    return reject('Duplicate Found');
                }
            }
        });
    });
});

bar.then((data) => {
    console.log('All done!');
});

In above code I am returning query + resolve/reject so it makes better to run in more synchronised way.
return conn.query(checkQuery, function (err, res) {

Plus, while processing this promise I am handling with .then((data) so I can handle that resolve values here.

bar.then((data) => {
    console.log('All done!');
});

Note: If you are rejecting any promise it won't be available in above .then block you'll find this reject in catch block so code will be changed in following way.

bar.then((data) => {
    console.log('All done!');
}).catch(err=>{
    console.log(err);
});
酷遇一生 2025-01-27 14:14:23

您可以尝试以下操作:


(async () => {

    await new Promise((resolve, reject) => {
        result.forEach((row, index, array) => {
            var escaped = _.map(row, mysql.escape);
            var checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = 
    " + escaped[0] + " AND field2 = " + escaped[1] + " AND field3 = " + 
escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " + escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
            conn.query(checkQuery, function (err, res) {
                if (err) {
                    console.log("Error checking row for duplicate");
                    console.log(checkQuery);
                    process.exit(1);
                } else {
                    if (res[0].found == 0) {
                        var query = " (";
                        var escaped = _.map(row, mysql.escape);
                        var csv = escaped.join(',');
                        query += csv;
                        query += ")";
                        query += row !== _.last(result) ? ',' : ';';
                        console.log(query);//This will change to inserting the data to the table
                    }else{
                        console.log("Duplicate found!");
                    }
                }
            });
            if (index === array.length -1) resolve();
        });
    });


        console.log('All done!');

})();

您甚至不需要调用 process.exit(0) 因为当作业完成时代码总是会终止:)

You can try the following:


(async () => {

    await new Promise((resolve, reject) => {
        result.forEach((row, index, array) => {
            var escaped = _.map(row, mysql.escape);
            var checkQuery = "SELECT COUNT(*) as found FROM data WHERE field1 = 
    " + escaped[0] + " AND field2 = " + escaped[1] + " AND field3 = " + 
escaped[2] + " AND field4 = " + escaped[3] + " AND field5 = " + escaped[4] + " AND field6 = " + escaped[5] + " AND field7  = " + escaped[6] + ";";
            conn.query(checkQuery, function (err, res) {
                if (err) {
                    console.log("Error checking row for duplicate");
                    console.log(checkQuery);
                    process.exit(1);
                } else {
                    if (res[0].found == 0) {
                        var query = " (";
                        var escaped = _.map(row, mysql.escape);
                        var csv = escaped.join(',');
                        query += csv;
                        query += ")";
                        query += row !== _.last(result) ? ',' : ';';
                        console.log(query);//This will change to inserting the data to the table
                    }else{
                        console.log("Duplicate found!");
                    }
                }
            });
            if (index === array.length -1) resolve();
        });
    });


        console.log('All done!');

})();

You don't even need to call the process.exit(0) because the code will always terminate when the job is done :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文