/ uazw blog / why we need promise

why we need promise

2015-09-15 posted in []

promise save me from deep

要说到异步编程大家可能第一时间想到的就是javasrcipt, 比如在web的时候我们经常写ajax的代码去和后台交互, 或者再用node的时候,用到里面的异步版本(强调非同步)的函数。但是这种callback的写法很容易出现嵌套多次的情况出现。

以下我们考虑实现一个简单版本的文件复制(node)。

function unlyAsyncVersion(sourcePath, targetPath) {
    fs.readFile(sourcePath, function (err, data) {
        if (err) {
            console.error(err);
        } else {
            fs.writeFile(targetPath, data, function (err) {
                if (err) {
                    console.error(err);                    
                } else {
                    console.log('success');
                }
            });
        }
    })
}
unlyVersion("d:/2.txt", "d:/3.txt");

在这段代码中,我们将所有的逻辑埋藏在一个个回调函数中。

function promiseUnlyVersion(sourcePath, targetPath) {
    var promise = new Promise(function (reslove, reject) {
        fs.readFile(sourcePath, function (err, data) {
            if (err) {
                reject(err);
            } else {
                reslove(data);
            }
        });
    });
    
    promise.then(function (data) {
        var promise = new Promise(function (reslove, reject) {
            fs.writeFile(targetPath, data, function (err) {
                if (err) {
                    reject(err);
                } else {
                    reslove();
                }
            });            
        })
    return promise;
    }, console.error).
    then(function () {console.log('success');}, function (err) {console.log(err);});
}
promiseVersion("d:/2.txt", "d:/3.txt");

然而好像promise并不是救世主?所以干嘛要用它!?因为他给于我们能写出优化代码的能力

function promiseBetterVersion(sourcePath, targetPath) {    
    openHelper().
    then(writeHelper, console.error).
    then(function () { console.log("success") }, console.error);

    function openHelper() {
        return new Promise(function (reslove, reject) {
            fs.readFile(sourcePath, function (err, data) {
                if (err) {
                    reject(err);
                } else {
                    reslove(data);
                }
            });
        })
    }
    
    function writeHelper(data) {
        return new Promise(function (reslove, reject) {
            fs.writeFile(targetPath, data, function (err) {
                if (err) {
                    reject(err);
                } else {
                    reslove();
                }
            });            
        });
    }
}

promiseBetterVersion("d:/2.txt", "d:/3.txt");

promise save me from exception

另一方面我们用promise的原因在于我们在写异步代码所遇到的尴尬问题。

function catchMeWithLuck() {
    try {
        fs.readFileSync('notExisted.txt');
    } catch (err) {
        console.log(err);
    }
}
catchMeWithLuck();

在以上的同步版本代码中,因为文件不存在而抛出的异常,是可以捕获到的。

function catchMeWithNotLuck() {
    try {
        fs.readFile('notExisted.txt', function (err, data) {
            if (err) {
                throw err;
            } else {
                console.log(data);
            }
        });
    } catch (err) {
        console.log(err);
    }
}

catchMeWithNotLuck();

然而在异步代码中,相同的异常却无法捕获到,这是因为函数执行的时候已经远离了异常捕获的范围

那么怎么办呢?很可以你会想到以下写法,将异常信息和正常结果通过返回值返回。

function myReadFile(filename) {
    var result = {
            'hasError': true,
            'message': '';}
    try {
        result['message'] = fs.readFileSync(filename);
        result['hasError'] = false;
    } catch (err) {
        result['message'] = err;
        result['hasError'] = true;
    }
}

function callMyReadFile() {
    var result = myReadFile('afile');
    if (result['hasError']) {
        // deal with exception
    } else {
        // do something...
    }
}

callMyReadFile()

那么Promise我们该怎么解决呢,正如我们在promiseBetterVersion中看到的那样, 通过将实际的逻辑分离出来promise的逻辑就可以很清晰.