使用回调地狱转换构建来承诺地狱

时间:2016-05-04 22:45:12

标签: javascript node.js promise ecmascript-6 bluebird

我目前正在将一个构建过程转换为一些回调地狱变成承诺地狱(地狱很可能是因为我对承诺不熟悉而且我对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);
                    });
                });
            });
        });
    });
});

2 个答案:

答案 0 :(得分:3)

你被欺骗如何运作所欺骗。首次执行javascript时,会构建链的所有部分。因为,在构建链条时,您会致电rcopyAsyncrcopyAsync会立即开始。如果您希望稍后发生某些事情,则需要将其包装在.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')
    ]);
})
...

您想要推迟执行。如果你在函数包装器之外做某事,那么它将立即执行。如果将它放在函数包装器中,它将只在前一个调用完成后执行。

答案 1 :(得分:1)

ES2017具有async/await语法

  

防止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'))