第三章 Promise 的优势

1 指定回调函数的方式更加灵活

旧的:必须在启动异步任务前指定。

Promsie:启动异步任务 => 返回 Promise 对象 => 给 Promise 对象绑定回调函数(可以在异步任务完成后指定回调函数,甚至可以指定多个回调函数)。

// 成功的回调函数
function successCallback(result) {
    console.log("声音文件创建成功: " + result);
}
// 失败的回调函数
function failureCallback(error) {
    console.log("声音文件创建失败: " + error);
}

/* 1.1 使用纯回调函数 (旧的方式) */
createAudioFileAsync(audioSettings, successCallback, failureCallback)

/* 1.2. 使用Promise */
const promise = createAudioFileAsyncPromise(audioSettings);  // 异步任务已经执行
promise.then(successCallback, failureCallback);   // 通过调用 then 方法才能执行回调函数

Promise 方式我们可以在任意时刻执行回调函数,哪怕异步任务已经完成了一段时间

// 返回 Promise 对象,此时异步任务已经执行
const promise = createAudioFileAsync(audioSettings);  
// 5s 之后再执行回调函数,哪怕这个时候可能异步已经完成一段时间了 
setTimeout(() => {
    promise.then(successCallback, failureCallback);
}, 5000);

Promise 对象通过多次调用 then 方法,就可以指定多个回调函数,它们会按照插入顺序执行。

// 返回 Promise 对象
const promise = createAudioFileAsync(audioSettings);  
// 通过 then 方法指定回调函数
promise.then(successCallback, failureCallback);
// 再次通过 then 方法指定回调函数
promise.then(successCallback1, failureCallback1);

案例:读取文件

const util = require('util');
const fs = require('fs');

// 读取文件返回 Promise 对象
let result = util.promisify(fs.readFile)('./content.txt');

setTimeout(() => {
    result.then((data) => {
        console.log('至少5s之后读取文件内容:' + data);
    })
}, 5000);

result.then((data) => {
    console.log('读取文件内容:' + data);
});
result.then((data) => {
    console.log('再次文件内容:' + data);
});

2 支持链式调用,可以解决回调地狱问题

1. 什么是回调地狱?

回调函数嵌套调用,外部异步执行的结果是嵌套异步操作的条件。

2. 回调地狱的缺点?

  • 不便于阅读
  • 不便于异常处理

3. 解决方案?

Promsie 链式调用

4. 终极解决方案?

async/await

/* 
1. 回调地狱
*/
doSomething(function(result) {
    doSomethingElse(result, function(newResult) {
        doThirdThing(newResult, function(finalResult) {
            console.log('Got the final result: ' + finalResult)
        }, failureCallback)
    }, failureCallback)
}, failureCallback)

/* 
2. 使用promise的链式调用解决回调地狱
*/
doSomething().then(function(result) {
    return doSomethingElse(result)
})
.then(function(newResult) {
    return doThirdThing(newResult)
})
.then(function(finalResult) {
    console.log('Got the final result: ' + finalResult)
})
.catch(failureCallback)

/* 
3. async/await: 回调地狱的终极解决方案
*/
async function request() {
    try {
        const result = await doSomething()
        const newResult = await doSomethingElse(result)
        const finalResult = await doThirdThing(newResult)
        console.log('Got the final result: ' + finalResult)
    } catch (error) {
      failureCallback(error)
    }
}

案例:按顺序读取多个个文件

/** 
 * 因为读取文件是异步操作,必须在读取完第一个文件之后再去读取第二个文件,才能实现按照顺序读取。
 * 旧的写法必然造成回调地狱
*/

const fs = require('fs');

fs.readFile('./content1.txt', (err, data)=>{
    if (err) throw err;
    console.log('第一个文件内容:' + data);
    fs.readFile('./content2.txt', (err, data)=>{
        if (err) throw err;
        console.log('第二个文件内容:' + data);
        fs.readFile('./content4.txt', (err, data)=>{
            if (err) throw err;
            console.log('第三个文件内容:' + data);
        });
    });
});
/** 
 * Promise 对象链式调用 then 方法,解决回调地狱。
*/
const util = require('util');
const fs = require('fs');

const readFile = util.promisify(fs.readFile);

readFile('./content1.txt').then(data => {
    console.log('第一个文件内容:' + data);
    return readFile('./content2.txt');
}).then(data => {
    console.log('第二个文件内容:' + data);
    return readFile('./content3.txt');
}).then(data => {
    console.log('第三个文件内容:' + data);
}).catch(error => {
    console.log('读取失败:' + error);
});

results matching ""

    No results matching ""