ES6:手撸Promise

591 阅读3分钟

Promise 对象用于表示一个异步操作的最终完成 (或失败)及其结果值。

一、概述

①一个 Promise 对象代表一个在这个 promise 被创建出来时不一定已知的值。它让您能够把异步操作最终的成功返回值或者失败原因和相应的处理程序关联起来。 这样使得异步方法可以像同步方法那样返回值:异步方法并不会立即返回最终的值,而是会返回一个 promise,以便在未来某个时候把值交给使用者。

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

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

image.png

二、源码

1、promise()

  • 使用promise能够有效的解决js异步回调地狱问题
  • 能够将业务逻辑与数据处理分隔开使代码更优雅,方便阅读,更有利于代码维护

①基本用法

function promiseTest() { 
    let promise = new Promise((resolve, reject) => { 
        let r = parseInt(Math.random() * 10) 
        if (r % 2 == 0) { 
            resolve('成功') 
        } else { 
            reject('失败') 
        } 
    }) 
    return promise 
} 
const promise = promiseTest()
promise.then((data) => { 
    console.log(data) 
}).catch((err) => { 
    console.log(err) 
})

②规范

class Mypromise { 
    constructor(executor) { 
        this.state = 'pending' //状态值 
        this.value = undefined //成功的返回值 
        this.reason = undefined //失败的返回值 
        // 成功 
        let resolve = (value) => { 
            if (this.state == 'pending') { 
                this.state = 'fullFilled';
                this.value = value;
            } 
        } 
        // 失败 
        let reject = (reason) => { 
            if (this.state == 'pending') { 
                this.state = 'rejected'; 
                this.reason = reason; 
            } 
        } 
        try { 
            // 执行函数 
            executor(resolve, reject) 
        } catch (err) {
            // 失败则直接执行reject函数 
            reject(err) 
        } 
    } 
    then(onFullFilled, onRejected) { 
        // 状态为fulfuilled,执行onFullFilled,传入成功的值
        if (this.state == 'fullFilled') { 
            onFullFilled(this.value) 
        } 
        // 状态为rejected,执行onRejected,传入失败的值 
        if (this.state == 'rejected') { 
            onRejected(this.reason) 
        } 
    } 
} 
const p = new Mypromise((resolve, reject) => { 
    // resolve('success') 
    // 走了成功就不会走失败了 throw new Error('失败') 
    // 失败了就走resolve 
    reject('failed');
    // 走了失败就不会走成功 
 }) 
 p.then((res) => { 
     console.log(res) 
 }, (err) => { 
     console.log(err) 
 })

③完整代码

class Mypromise { 
   constructor(executor) { 
        this.state = 'pending'; //状态值 
        this.value = undefined; //成功的返回值 
        this.reason = undefined; //失败的返回值
        this.onResolvedCallbacks = [];//成功的回调函数 
        this.onRejectedCallbacks = []; //失败的回调函数
        // 成功 
        let resolve = (value) => { 
            // pending用来屏蔽的,resolve和reject只能调用一个,不能同时调用,这就是pending的作用
            if (this.state == 'pending') { 
                this.state = 'fullFilled';
                this.value = value;
                this.onResolvedCallbacks.forEach(fn => fn())// 发布执行函数 
            } 
        } 
        // 失败 
        let reject = (reason) => { 
            if (this.state == 'pending') { 
                this.state = 'rejected'; 
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn => fn())//失败执行函数
            } 
        } 
        try { 
            // 执行函数 
            executor(resolve, reject) 
        } catch (err) {
            // 失败则直接执行reject函数 
            reject(err) 
        } 
    } 
    then(onFullFilled, onRejected) { 
       // 同步
       if (this.state == 'fullFilled') { 
          onFullFilled(this.value) 
       } 
       // 状态为rejected,执行onRejected,传入失败的值 
       if (this.state == 'rejected') { 
          onRejected(this.reason) 
       } 
       // 异步 
       if (this.status == 'pending') { 
           // 在pending状态的时候先订阅 
           this.onResolvedCallbacks.push(() => { 
               // todo 
               onFullFilled(this.value) 
           }) 
           this.onRejectedCallbacks.push(() => { 
               // todo 
               onRejected(this.reason) 
           }) 
       }
    } 
}    
const p = new Mypromise((resolve, reject) => { 
    setTimeout(function() { 
        // resolve('success') 
        // 异步调用的时候,this.status一直是pending状态,不会执行代码了,因此要改装成发布订阅者模式 
        reject('failed') 
     }, 1000) 
     // resolve('success') 
     // 走了成功就不会走失败了 
     // throw new Error('失败')  失败了也会走resolve 
     // reject('failed') 
}) 
p.then((res) => { 
    console.log(res) 
}, (err) => { 
    console.log(err) 
}) p.then((res) => { 
    console.log(res) 
}, (err) => { 
    console.log(err) 
}) p.then((res) => { 
    console.log(res) 
}, (err) => { 
    console.log(err) 
})

2、promise.all(),集合多个 promise 的返回结果时很有用。

function myPromiseAll(promiseList){
    return new Promise((resolve,reiect)=>{
        let resArr = [];
        let num = 0;
        promiseList.forEach(item => {
            item.then(res => {
                resArr.push(res);
                num++;
                if(num === promiseList.length) {
                    resolve(resArr);
                }
            })
        })
    })
}
myPromiseAll([p1,p2]).then(res => {
    console.log(res);
})

Promise.all() 方法接收一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入,并且只返回一个Promise实例, 那个输入的所有promise的resolve回调的结果是一个数组。