为什么第27行在第24行之前执行?

我与JavaScript的初学者,并尝试build立一个干净的对象,在我的使用情况下使用Dockerode库。 我在这里有一个asynchronous问题,我的第27行在24之前执行,我不明白为什么以及如何解决它!

另外,如果你更容易,请访问这个公共要点: https : //gist.github.com/msitruk/2cdb655a0bebdb29c61d8bc5606a2695

const Docker = require('dockerode'); const docker = new Docker({ socketPath: '/var/run/docker.sock' }); // CONSTRUCTOR function SearchUtils() { this.listContainersPromise = docker.listContainers({all: true}); this.scraperListId = []; } // "METHODS" SearchUtils.prototype.run = function() { this.getScraperContainersListPromise() .then((containers) => { for (let i = 0; i < containers.length; i++) { if (containers[i].Names.toString().indexOf("scraper") !== -1) { this.addToScraperList(containers[i].Id, "wait"); } } }, (err)=>{console.log(err)}) .then(()=>{ this.checkReadyScraper(); },(err)=>{console.log(err)}) .then(() => { this.scrap(); }, (err)=>{console.log(err)}); }; SearchUtils.prototype.checkReadyScraper = function() { for (let i = 0; i < this.scraperListId.length; i++) { this.exec("getStatus", this.scraperListId[i].id); } }; SearchUtils.prototype.getScraperContainersListPromise = function() { return this.listContainersPromise; // <- Not working }; SearchUtils.prototype.exec = function(type, containerId){ let container = docker.getContainer(containerId); if (type === "getStatus"){ this.runExec(container, 'cat /home/immobot/status'); } else if (type === "scrap") { this.runExec(container, 'torify scrapy crawl seloger -o seloger.json'); } }; SearchUtils.prototype.scrap = function() { let localRdyScraperList = []; for (let i = 0; i < this.scraperListId.length; i++) { if(this.scraperListId[i].status.toString('utf8').indexOf("ready") !== -1){ localRdyScraperList.push(this.scraperListId[i].id); } } console.log("test de localRdyScraperList : "+localRdyScraperList); // this.exec("scrap", this.scraperListId[i].id); }; SearchUtils.prototype.addToScraperList = function(containerId,status) { this.scraperListId.push({id: containerId, status: status}); }; SearchUtils.prototype.getScraperList = function() { return this.scraperListId; }; SearchUtils.prototype.getScraperList = function() { return this.scraperListId; }; SearchUtils.prototype.runExec = function (container, cmd) { let options = { Cmd: [ '/bin/bash', '-c', cmd ], AttachStdout: true, AttachStderr: true }; container.exec(options, (err, exec) => { if (err) return; exec.start((err, stream) => { if (err){ console.log("error : "+err); return; } // container.modem.demuxStream(stream, process.stdout, process.stderr) if (cmd === "cat /home/immobot/status"){ let newStream = require('stream'); let logStream = new newStream.PassThrough(); logStream.on('data', (chunk) => { // console.log(chunk.toString('utf8')); if (chunk.toString('utf8').indexOf("ready") !== -1){ console.log("CONTAINER READY !!"); //EDIT CONTAINER STATUS IN SCRAPERLIST TO READY this.changeStatusToReady(container.id); } }); container.modem.demuxStream(stream, logStream, process.stderr); } else if (cmd === "torify scrapy crawl seloger -o seloger.json"){ console.log("on lance le scrape sur un des scraper rdy"); container.modem.demuxStream(stream, process.stdout, process.stderr) } // container.modem.demuxStream(stream, logStream, process.stderr); exec.inspect(function(err, data) { if (err){ console.log("error : "+err); return; } }); }); }); }; SearchUtils.prototype.changeStatusToReady = function (containerId){ for (let i = 0; i < this.scraperListId.length; i++) { if(this.scraperListId[i].id === containerId){ this.scraperListId[i].status = "ready"; } } // console.log(this.getScraperList()); }; module.exports = SearchUtils; 

如果你的链接承诺,不要忘记返回你的下一个承诺..

例如..

 .then(()=>{ this.checkReadyScraper(); } 

如果checkReadyScraper()是一个承诺,那么你会想要返回它。

例如。

 .then(()=>{ return this.checkReadyScraper(); } 

否则,你所做的就是运行checkReadyScraper()并完全忽略返回的Promise。

这是我认为你的runExec应该看起来。 我假设exec.inspect是你想解决的。

 SearchUtils.prototype.runExec = function (container, cmd) { return new Promise ((resolve, reject)=>{ let options = { Cmd: [ '/bin/bash', '-c', cmd ], AttachStdout: true, AttachStderr: true }; container.exec(options, (err, exec) => { if (err) return reject(err); //return error exec.start((err, stream) => { if (err){ console.log("error : "+err); return reject(err); //return error } // container.modem.demuxStream(stream, process.stdout, process.stderr) if (cmd === "cat /home/immobot/status"){ let newStream = require('stream'); let logStream = new newStream.PassThrough(); logStream.on('data', (chunk) => { // console.log(chunk.toString('utf8')); if (chunk.toString('utf8').indexOf("ready") !== -1){ console.log("CONTAINER READY !!"); //EDIT CONTAINER STATUS IN SCRAPERLIST TO READY this.changeStatusToReady(container.id); } }); container.modem.demuxStream(stream, logStream, process.stderr); } else if (cmd === "torify scrapy crawl seloger -o seloger.json"){ console.log("on lance le scrape sur un des scraper rdy"); container.modem.demuxStream(stream, process.stdout, process.stderr) } // container.modem.demuxStream(stream, logStream, process.stderr); exec.inspect(function(err, data) { if (err){ console.log("error : "+err); //don't forget to return the rejection return reject(err); } //looks like everything was ok, lets resolve resolve(data); }); }); }); //resolve("ok"); too early // TODO ADD EROR STRATEGY //reject("error"), pointless }); }; 

执行一个任务(在你的代码的第81行中使用container.exec),与其余的步骤不同步,在完成时有一个callback。 如果订单非常重要,那么在运行废料命令之前,您必须确保所有的刮板检查都已完成。

首先 – 在每次()调用中都不需要处理错误。 您可以实现一个错误捕获,这将捕获序列中任何then()项中的错误:

 .then(()=> { this.checkReadyScraper(); }) .then(() => { this.scrap(); }) .catch(e => console.log(e)) 

还要注意,像catch这样的箭头函数(e => console.log(e))不需要{}和;

你的问题是你的任务是asynchronous。 如果你想连锁任务 – 你应该做一个任务返回一个承诺

这是一个粗略的例子,你应该重构:

 //Should return Promise SearchUtils.prototype.exec = function(type, containerId){ let container = docker.getContainer(containerId); if (type === "getStatus"){ //runExec should return us a Promise return this.runExec(container, 'cat /home/immobot/status'); } else if (type === "scrap") { return this.runExec(container, 'torify scrapy crawl seloger -o seloger.json'); } }; SearchUtils.prototype.runExec = function (container, cmd) { return new Promise(function(resolve, reject) { //do some stuff //then call resolve(result) //or call reject(error) }); } 

在此之后,你将能够链接Promises(这实际上是相当真棒,并有助于解决callback地狱):

 .then(()=> { //this not returns Promise, and it will be correctly chained return this.checkReadyScraper(); }) .then(() => { //this not returns Promise, and it will be correctly chained return this.scrap(); }) .catch(e => console.log(e)) 

此外,为了使这个看起来更干净,我甚至build议做一些小的重构,最终会给你oneliner:

 .then(this.checkReadyScraper).then(this.scrap).catch(console.log) 
Interesting Posts