第二章 Promise 基本使用

1 基本编码流程

// 1) 实例化 Promise 对象, 指定执行器函数
let p = new Promise((resolve, reject) => {
    // 2) 在执行器函数中启动异步任务
    setTimeout(() => {
        let n = Math.floor(Math.random() * 10);  //随机生成一个数字 
        // 3) 根据结果做不同处理
        if (n % 2 === 0) {
            // 3.1) 如果 n 是偶数认为是成功的,调用 resolve(),传入成功的 value, 状态变为 resolved
            resolve(n);
        } else {
            // 3.2) 如果 n 是奇数认为是失败的,调用 reject(),传入失败的 reason, 状态变为 rejected
            reject(n);
        }
    }, 2000);
});

// 4) 指定成功或失败的回调函数,状态改变回调函数会执行
p.then(value => {  // 状态是 resolved,调用此回调函数  
    console.log('成功的 value:'+value)
}, reason => {  // 状态是 rejected,调用此回调函数
    console.log('失败的 reason:' + reason);
});

我们也可以把上述操作封装在一个函数中,让函数返回一个 Promsie 对象。

function doDelay(time) {
    // 1) 创建 Promise 对象, 并把创建的对象返回
    return new Promise((resolve, reject) => {
        // 2) 在执行器函数中启动异步任务
        setTimeout(() => {
            const time = Math.floor(Math.random() * 10);  //随机生成一个数字 
            // 3) 根据结果做不同的处理
            if (time % 2 === 0) {
                // 3.1) 成功了就调用 resolve 并传入 value, 状态改为 resolved
                resolve(time);
            } else {
                // 3.2) 失败了就调用 reject 并传入 reason,状态改为 rejected 
                reject(time);
            }
        }, time);
    });
}

// 调用函数返回一个 Promise 对象
const p = doDelay(2000);

// 指定成功或失败的回调函数,状态改变回调函数会执行
p.then(value => {  // 状态是 resolved,调用此回调函数  
    console.log('成功的 value:'+value)
}, reason => {  // 状态是 rejected,调用此回调函数
    console.log('失败的 reason:' + reason);
});

2 案例:使用 Promise 封装 Ajax

/**
 * 可复用的 Ajax 请求函数, 只实现 GET 请求
 * @param url 请求地址
 * @return Promsie 对象 
 */
function promiseAjax(url, data) {
    return new Promise((resolve, reject) => {
        // 创建 XMLHttpRequest对象
        const xhr = new XMLHttpRequest();
        // 监听状态变化事件
        xhr.onreadystatechange = () => {
            // 如果响应结束
            if (xhr.readyState === 4) {
                // 响应状态码是2xx则表示成功(resolved),否则错误(rejected)
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText);
                } else {
                    reject(new Error('请求失败:status:' + xhr.status));
                }
            }
        };
        // 初始化请求
        xhr.open('GET', url);
        // 发送请求
        xhr.send();
    })
}

// 调用函数
promiseAjax('https://api.apiopen.top/getAllUrl').then(data => {
    console.log(data);
}, error => {
    console.log(error);
});

3 案例:使用 Promsie 封装文件读取(Node)

// 引入模块
const fs = require('fs');

// 创建 Promise 对象
let p = new Promise((resolve, reject) => {
    // 在执行器函数中启动异步任务(异步读取文件)
    fs.readFile('./content.txt', (err, data) => {
        // 根据读取结果进行不同的处理
        if (err) {
            reject(err);
        } else {
            resolve(data)
        }
    });
});

// 调用 then 方法
p.then((data) => {
    console.log('文件内容:\n' + data);
}, (error) => {
    console.log('读取失败:\n' + error);
});

我们仍然可以定义一个可复用的函数,返回 Promise 对象

/**
 * 读取文件
 * @param {string} filename
 * @param {Promise} 一个 Promise 对象  
 */
function promiseReadFile(filename){
    // 引入模块
    const fs = require('fs');
    // 创建 Promise 对象 并返回
    return new Promise((resolve, reject) => {
        // 在执行器函数中启动异步任务(异步读取文件)
        fs.readFile(filename, (err, data) => {
            // 根据读取结果进行不同的处理
            if (err) {
                reject(err);
            } else {
                resolve(data)
            }
        });
    }); 
}

// 读取文件操作
promiseReadFile('./content.txt').then((data) => {
    console.log('文件内容:\n' + data);
}, (error) => {
    console.log('读取失败:\n' + error);
});

Node 中有一个核心模块 util,util 中有一个方法 promisify,该方法可以传入一个遵循常见的错误优先的回调风格的函数(即以 (err, value) => ... 回调作为最后一个参数),然后得到一个返回 Promise 对象的函数。

// 导入模块
const util = require('util');
const fs = require('fs');

// 使用 util.promisify 处理 fs.readFile, 得到的 readFile 就是一个返回 Promise 对象的函数
const readFile = util.promisify(fs.readFile);

// 调用 readFile 函数读取文件
readFile('./content.txt').then((data) => {
    console.log('读取内容如下:\n' + data);
}, (error) => {
    console.log('读取失败:' + error);
});

results matching ""

    No results matching ""