Promise复杂使用

106 阅读2分钟

最近在做 electron 开发,采用的是 electron + vue 两个独立工程的架构。在安装依赖时,涉及到 electron工程的依赖, vue工程的依赖还有在 win32 架构中指定安装 32 位的 electron。 在写安装依赖脚本时,使用了 Promise,所以这里对 Promise 的用法做一个总结。

Promise 概念

Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。这里更详细的可以参考 MDN 官方文档

Promise必然处于以下几种状态之一:

  • 待定(pending): 初始状态,既没有被兑现,也没有被拒绝。
  • 已兑现(fulfilled): 意味着操作成功完成。 => resolve()
  • 已拒绝(rejected): 意味着操作失败。 => reject()

Promise 链式调用

我们可以用 promise.then(),promise.catch() 和 promise.finally() 这些方法将进一步的操作与一个变为已敲定状态的 promise 关联起来。这些方法还会返回一个新生成的 promise 对象,这个对象可以被非强制性的用来做链式调用。

NOTE: 当 .then() 中缺少能够返回 promise 对象的函数时,链式调用就直接继续进行下一环操作。

Promise 常用方法

  • 。。。

  • Promise.all([array]) 返回 Promise,当 array 里所有的 Promise 都 resolve 才会触发。

  • Promise.any([array]) 返回 Promise, 当 array 里其中一个 Promise 结果为 resolve 就会触发。

Promise 使用例子

有 funcA, funcB, funcC 三个基本方法,要求:

  1. 顺序执行 funcA, funcB, funcC。
  2. 同步执行 funcA, funcB, 再执行 funcC。
  3. 步骤 1 执行完,再执行 步骤 2。
  4. 调用过程所有 error 统一处理。

下面分别用 3 种方法实现。

  • 方法一: then 链式调用, 但是代码比较繁琐。

  • 方法二: 构建了调用 queue,代码精简。

  • 方法三: 使用 await async 方式构建调用 queue。

    NOTE: 
    这里需要注意的是,在方法二和方法三中,传入的参数需要是 FUNCTION, 而不是 FUNCTION 执行后的结果。
    因为要确保方法的执行顺序,所以需要 FUNCTION 在 promise 里执行。
      
    

具体代码如下,也可以参考 Gist

// promise.js

// Method 1
// callInThenChain();

// Method 2
callInQueue();

// Method 3
// callInAsyncAwait();

function funcA() {
    return new Promise((resolve, reject) => {
        try {
            console.log('Exec funcA');
            resolve('a');
        } catch (error) {
            reject(error);
        }
    });
}


function funcB() {
    return new Promise((resolve, reject) => {
        try {
            console.log('Exec funcB');
            resolve('b');
        } catch (error) {
            reject(error);
        }
    });
}

function funcC() {
    return new Promise((resolve, reject) => {
        try {
            console.log('Exec funcC');
            resolve('c');
        } catch (error) {
            reject(error);
        }
    });
}

function funcD() {
    return new Promise((resolve, reject) => {
        try {
            console.log('Exec funcD, test promise in promise');
            // call funcA and funcB async
            Promise.all([funcA(), funcB()])
                .then(function () {
                    // call funcC sync
                    return funcC();
                })
                .then(function () {
                    // must call resolve to return thenable
                    resolve('d');
                })
                .catch((error) => reject(error));
        } catch (error) {
            reject(error);
        }
    });
}

function callInThenChain() {
    console.log('> Call in then chain, the code is cumbersome. \n\n');
    Promise.resolve()
        .then(function () {
            return funcA();
        })
        .then(() => {
            console.log('The chain will go on if not return promise');
        })
        .then(function () {
            return funcB();
        })
        .then(() => funcC())
        .then(() => funcD())
        .then((result) => console.log(`Finish ${result}`))
        .catch(error => {
            console.log(`Error: ${error}`);
        })
}

function callInQueue() {
    console.log('> Call in queue\n\n');
    function queue(arr) {
        var queue = Promise.resolve()
        arr.forEach(function (item) {
            queue = queue.then(item)
        })
        return queue;
    }

    // NOTE: pass FUNCTION not execed function.
    queue([funcA, funcB, funcC, funcD])
        .then((result) => console.log(`Finish ${result}`))
        .catch(error => {
            console.log(`Error: ${error}`);
        })
}

function callInAsyncAwait() {
    async function queue(arr) {
        let res = []
        for (let fn of arr) {
            var data = await fn();
            res.push(data);
        }
        return await res
    }

    // NOTE: pass FUNCTION not execed function.
    queue([funcA, funcB, funcC, funcD])
        .then((result) => console.log(`Finish ${result}`))
        .catch(error => {
            console.log(`Error: ${error}`);
        })
}