使用回调地狱将构建转换为承诺地狱
Converting a build using callback hell to promise hell
我目前正在将带有回调地狱的构建过程转换为 promise 地狱(地狱很可能是因为我是 promises 的新手而且我对 Bluebird 缺乏经验)。我正在努力通过 .all
方法,但出现文件已存在的错误。也许其中的文件副本试图在开始时 rimraf
之前发生?
const Promise = require('bluebird');
const rcopyAsync = Promise.promisify(require('recursive-copy'));
const readAsync = Promise.promisify(require('recursive-readdir'));
const rmrfAsync = Promise.promisify(require('rimraf'));
const globAsync = Promise.promisify(require('glob'));
rmrfAsync('{build,dist}')
.then(() => {
return readAsync('src');
})
.then((files) => {
if (!files.length) {
return Promise.reject(new Error('No source to compile.'));
}
return Promise.resolve(true);
})
.all([
rcopyAsync(`${__dirname}/scripting`, 'build'),
rcopyAsync(`${__dirname}/compiler/${process.platform}`, 'build'),
rcopyAsync('src/scripting', 'build')
])
.then(() => {
return globAsync('*.sma', { cwd: 'build' });
})
.then((files) => {
console.log(files);
})
.catch(err => {
throw err;
});
对于任何感兴趣的人,回调地狱的工作部分如下:
...
rmrf('{build,dist}', err => {
if (err) throw err;
read('src', (err, files) => {
if (err) throw err;
if (!files.length) return;
rcopy(`${__dirname}/scripting`, 'build', err => {
if (err) throw err;
rcopy(`${__dirname}/compiler/${process.platform}`, 'build', err => {
if (err) throw err;
rcopy('src/scripting', 'build', err => {
if (err) throw err;
glob('*.sma', { cwd: 'build' }, (err, files) => {
if (err) throw err;
console.log(files);
});
});
});
});
});
});
你被 promises 的工作原理欺骗了。当您第一次执行 javascript 时,链的所有部分都已构建。因为,在构建你的链时,你调用rcopyAsync
,rcopyAsync
会立即开始。如果您希望稍后发生某些事情,则需要将其包装在 .then
中。
rmrfAsync('{build,dist}')
.then(() => {
return readAsync('src');
})
.then((files) => {
if (!files.length) {
/* Could even be:
throw new Error('No source to compile');
*/
return Promise.reject(new Error('No source to compile.'));
}
})
.then(() => {
// Wait until the previous promise finished before starting the rcopyAsync
return Promise.all([
rcopyAsync(`${__dirname}/scripting`, 'build'),
rcopyAsync(`${__dirname}/compiler/${process.platform}`, 'build'),
rcopyAsync('src/scripting', 'build')
]);
})
...
您想推迟执行死刑。如果你在函数包装器之外做一些事情,那么它将立即执行。如果将它放在函数包装器中,它只会在上一个调用完成后执行。
ES2017 有 async/await
语法
To prevent Promise hell
所以,你的代码应该是
async function foo() {
await rmrfAsync('{build,dist}')
var files = await readAsync('src')
if (!files.length)
throw new Error('No source to compile.');
await Promise.all([
rcopyAsync(`${__dirname}/scripting`, 'build'),
rcopyAsync(`${__dirname}/compiler/${process.platform}`, 'build'),
rcopyAsync('src/scripting', 'build')
])
var files = await globAsync('*.sma', { cwd: 'build' })
console.log(files)
return files
}
foo()
.then(files => something(files))
.catch(e => console.log('throw errors or rejecteds'))
我目前正在将带有回调地狱的构建过程转换为 promise 地狱(地狱很可能是因为我是 promises 的新手而且我对 Bluebird 缺乏经验)。我正在努力通过 .all
方法,但出现文件已存在的错误。也许其中的文件副本试图在开始时 rimraf
之前发生?
const Promise = require('bluebird');
const rcopyAsync = Promise.promisify(require('recursive-copy'));
const readAsync = Promise.promisify(require('recursive-readdir'));
const rmrfAsync = Promise.promisify(require('rimraf'));
const globAsync = Promise.promisify(require('glob'));
rmrfAsync('{build,dist}')
.then(() => {
return readAsync('src');
})
.then((files) => {
if (!files.length) {
return Promise.reject(new Error('No source to compile.'));
}
return Promise.resolve(true);
})
.all([
rcopyAsync(`${__dirname}/scripting`, 'build'),
rcopyAsync(`${__dirname}/compiler/${process.platform}`, 'build'),
rcopyAsync('src/scripting', 'build')
])
.then(() => {
return globAsync('*.sma', { cwd: 'build' });
})
.then((files) => {
console.log(files);
})
.catch(err => {
throw err;
});
对于任何感兴趣的人,回调地狱的工作部分如下:
...
rmrf('{build,dist}', err => {
if (err) throw err;
read('src', (err, files) => {
if (err) throw err;
if (!files.length) return;
rcopy(`${__dirname}/scripting`, 'build', err => {
if (err) throw err;
rcopy(`${__dirname}/compiler/${process.platform}`, 'build', err => {
if (err) throw err;
rcopy('src/scripting', 'build', err => {
if (err) throw err;
glob('*.sma', { cwd: 'build' }, (err, files) => {
if (err) throw err;
console.log(files);
});
});
});
});
});
});
你被 promises 的工作原理欺骗了。当您第一次执行 javascript 时,链的所有部分都已构建。因为,在构建你的链时,你调用rcopyAsync
,rcopyAsync
会立即开始。如果您希望稍后发生某些事情,则需要将其包装在 .then
中。
rmrfAsync('{build,dist}')
.then(() => {
return readAsync('src');
})
.then((files) => {
if (!files.length) {
/* Could even be:
throw new Error('No source to compile');
*/
return Promise.reject(new Error('No source to compile.'));
}
})
.then(() => {
// Wait until the previous promise finished before starting the rcopyAsync
return Promise.all([
rcopyAsync(`${__dirname}/scripting`, 'build'),
rcopyAsync(`${__dirname}/compiler/${process.platform}`, 'build'),
rcopyAsync('src/scripting', 'build')
]);
})
...
您想推迟执行死刑。如果你在函数包装器之外做一些事情,那么它将立即执行。如果将它放在函数包装器中,它只会在上一个调用完成后执行。
ES2017 有 async/await
语法
To prevent
Promise hell
所以,你的代码应该是
async function foo() {
await rmrfAsync('{build,dist}')
var files = await readAsync('src')
if (!files.length)
throw new Error('No source to compile.');
await Promise.all([
rcopyAsync(`${__dirname}/scripting`, 'build'),
rcopyAsync(`${__dirname}/compiler/${process.platform}`, 'build'),
rcopyAsync('src/scripting', 'build')
])
var files = await globAsync('*.sma', { cwd: 'build' })
console.log(files)
return files
}
foo()
.then(files => something(files))
.catch(e => console.log('throw errors or rejecteds'))