[英]Why line 27 is executed before line 24?
我初學javascript並嘗試構建一個干凈的對象,以便在我的用例中使用Dockerode庫。 我有一個異步問題,我的第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()
是一個promise,那么你會想要返回它。
例如。
.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 }); };
執行任務(使用container.exec,在代碼中的第81行),從其余步驟開始異步運行,完成后進行回調。 如果訂單很重要,您必須確保在運行scrap命令之前完成刮刀的所有檢查。
首先 - 不需要在每次then()調用中處理錯誤。 您可以實現單個錯誤捕獲,它將捕獲序列中任何then()項中的錯誤:
.then(()=> {
this.checkReadyScraper();
})
.then(() => {
this.scrap();
})
.catch(e => console.log(e))
另請注意,像catch(e => console.log(e))這樣的箭頭函數不需要{}和;
您的問題是您的任務是異步。 如果你想鏈接任務 - 你應該做一個任務來返回一個Promise
這是你應該重構的一個粗略的例子:
//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(這實際上非常棒,並有助於解決回調地獄):
.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))
另外,為了使這看起來更干凈,我甚至建議做一些小的重構,最終會給你oneliner:
.then(this.checkReadyScraper).then(this.scrap).catch(console.log)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.