您的位置:

Promises原理及实现

一、Promise基本概念

Promise 是异步编程的一种解决方案,用于处理异步操作。ES6 的 Promise 规范,是对异步编程的一种规范化,使得编写和维护异步程序更加容易、直观。

Promise 是一个对象,它代表了一个异步操作的最终结果。它可以是下列三种状态之一:等待态(pending)、完成态(fulfilled)、拒绝态(rejected)。

Promise 的优点在于可以避免“回调地狱”,使得代码结构清晰,更具有可读性和可维护性。

二、Promise基本用法

ES6 新增了 `Promise` 构造函数,可以使用 `new Promise()` 来创建一个 Promise 对象。

    
        let promise = new Promise(function(resolve, reject){
            //异步操作的代码
            //成功时调用 resolve()
            //失败时调用 reject()
        })
    

当 Promise 对象的状态发生改变时,会产生对应的回调函数。可以使用 `promise.then()` 方法来指定 Promise 对象状态变为 fulfilled 或 rejected 时调用的回调函数。这两个方法都返回一个新的 Promise 对象,可以进行链式调用。

    
        let promise = new Promise(function(resolve, reject){
            setTimeout(() => resolve("异步操作成功"), 1000);
        })

        promise.then(res => {
            console.log(res); //异步操作成功
        })
    

三、Promise原理

Promise 的基本原理就是对异步操作进行封装,使其可以返回一个 Promise 对象,并可以使用链式调用方法。

我们可以手动模拟一下 Promise 的内部实现:

    
        function Promise_old(fn){
            let state = 'pending';
            let value = null;
            let callbacks = [];

            this.then = function(onFulfilled){
                return new Promise_old(function(resolve){
                    handle({
                        onFulfilled: onFulfilled || null,
                        resolve: resolve
                    })
                })
            }

            function handle(callback){
                if(state === 'pending'){
                    callbacks.push(callback);
                    return;
                }

                if(!callback.onFulfilled){
                    callback.resolve(value);
                    return;
                }

                let ret = callback.onFulfilled(value);
                callback.resolve(ret);
            }

            function resolve(newValue){
                if(newValue && (typeof newValue === 'object' || typeof newValue === 'function')){
                    let then = newValue.then;
                    if(typeof then === 'function'){
                        then.call(newValue, resolve);
                        return;
                    }
                }

                setTimeout(function(){
                    state = 'fulfilled';
                    value = newValue;
                    callbacks.forEach(function(callback){
                        handle(callback);
                    })
                }, 0);
            }

            fn(resolve);
        }
    

上述代码中,我们定义了 `Promise_old` 构造函数。它内部定义了 `state`、`value`、`callbacks` 三个变量,分别记录 Promise 对象的当前状态、结果值和对应回调函数数组。同时我们定义了 `then` 方法,可以使用链式调用,将传入的回调函数压入 `callbacks` 数组中。

关键的 `handle` 函数则利用了 JavaScript 的事件循环机制,当 Promise 对象的状态从 `pending` 改变时,依次执行队列中的回调函数。

最后通过 `resolve` 函数,可以修改 Promise 对象的状态,触发对应回调函数的执行。

四、Promise实例应用

1、串行异步任务的处理

使用 `Promise` 可以让多个异步任务按顺序执行,比如读取多个文件,顺序进行操作。这里我们演示一个例子,读取两个文件,分别将其内容存放在一个数组中。

    
        let fs = require('fs');

        function readFile(filename){
            return new Promise(function(resolve, reject){
                fs.readFile(filename, 'utf8', function(err, data){
                    if(err){
                        reject(err);
                        return;
                    }
                    resolve(data);
                })
            })
        }

        Promise.all([
            readFile('file1.txt'),
            readFile('file2.txt')
        ]).then(function(dataArr){
            console.log(dataArr); //[data1, data2]
        })
    

2、并发异步任务的处理

有时候需要同时执行多个异步任务,可以使用 `Promise.all()` 方法,将返回值存放在数组中按顺序返回。

    
        let dataArr = [];

        function fetchData(url){
            return new Promise((resolve, reject) => {
                fetch(url)
                .then(res => res.json())
                .then(data => {
                    dataArr.push(data);
                    resolve(data);
                })
                .catch(error => reject(error))
            })
        }

        Promise.all([
            fetchData('https://api.xxx.com/1'),
            fetchData('https://api.xxx.com/2'),
            fetchData('https://api.xxx.com/3')
        ]).then(() => {
            console.log(dataArr); //[data1, data2, data3]
        })
    

3、Promise异常处理

使用 `then()` 方法时,可以链式调用多个回调函数,并在其中任何一个回调函数中引发错误,就会被 `catch()` 方法捕获。如果在 `then()` 方法中不使用回调函数,就必须在链头使用 `catch()` 方法来进行异常处理。

    
        function fetchData(){
            return new Promise((resolve, reject) => {
                //使用 Math.random() 模拟程序执行时出现错误
                if(Math.random() > 0.5){
                    resolve('fetch data success');
                } else {
                    reject('fetch data failed');
                }
            })
        }

        //这个方法捕获了两个 Promise 对象中的异常,并输出错误信息
        fetchData().then(res => {
            console.log(res);
        }).catch(error => {
            console.log(error);
        })
    

结束语

Promise 是异步编程的一种新规范,提高了代码的可读性、可维护性和稳定性。通过上述的介绍和实例,希望读者能够深入了解 Promise 的基本原理和使用方法,高效编写异步代码。