javascript异步解决方案之promise

js异步解决方案之promise

1. promise的定义

Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。javascript

参考java

理解:node

  • 没有异步就不须要promise。
  • Promise自己不是异步,只是咱们去编写异步代码的一种方式

2. promise 的规范

Es6将promise归入本身规范的时候,也遵循了一个相应的标准 — ``Promise A+规范。git

将其概括为4321规范github

4:4大术语 3:3种状态 2:2种事件 1:1个对象npm

2.1 四大术语

  1. 解决(fulfill):指一个 promise 成功时进行的一系列操做,如状态的改变、回调的执行。虽然规范中用 fulfill 来表示解决,但在后世的 promise 实现多以 resolve 来指代之。编程

  2. 拒绝(reject):指一个 promise 失败时进行的一系列操做。数组

  3. 终值(eventual value):所谓终值,指的是 promise 被解决时传递给解决回调的值,因为 promise 有一次性的特征,所以当这个值被传递时,标志着 promise 等待态的结束,故称之终值,有时也直接简称为值(value)。promise

  4. 据因(reason):也就是拒绝缘由,指在 promise 被拒绝时传递给拒绝回调的值。dom

2.2 3种状态

  • 等待态(Pending)
  • 执行态(Fulfilled)
  • 拒绝态(Rejected)

enter description here

针对每种状态的规范 等待态(Pending) 处于等待态时,promise 需知足如下条件:

  • 能够迁移至执行态或拒绝态

执行态(Fulfilled)

处于执行态时,promise 需知足如下条件:

  • 不能迁移至其余任何状态
  • 必须拥有一个不可变的终值

拒绝态(Rejected)

处于拒绝态时,promise 需知足如下条件:

  • 不能迁移至其余任何状态
  • 必须拥有一个不可变的据因

2.3 2种事件

针对3种状态,只有以下两种转换方向:

  • pending –> fulfilled
  • pendeing –> rejected

在状态转换的时候,就会触发事件。

若是是pending –> fulfiied,就会触发onFulFilled事件 若是是pendeing –> rejected,就会触发onRejected事件

2.4 1个对象

就是指promise对象

3. promise的基本用法

3.1 基本用法

let p = new Promise(function (resolve,reject) {
            reject("no");
        })
        console.log('p :', p);
复制代码

回调函数中的两个参数,其做用就是用于转换状态:

resolve,将状态从pending –> fullFilled reject,将状态从pending –> rejected

3.2 then 方法

在状态转换的时候,就会触发事件

若是是pending –> fulfiied,就会触发onFulFilled事件

若是是pendeing –> rejected,就会触发onRejected事件

针对事件的注册,Promise对象提供了then方法,以下:

enter description here

3.3promise典型定义

3.3.1 案例1:读取文件操做

const fs = require("fs");

let p = new Promise(function (resolve,reject) {
    fs.readFile("03-js基础/a.txt","utf8",(err,date)=>{
        if(err){
            reject(err);
        }else{
            resolve(date);
        }
    });
  });
  
  p.then(result=>{
      console.log('result :', result);
  }).catch(err=>{
      console.log('err :', err);
  });
复制代码

3.3.2 案例2:根据随机数返回结果

let p = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        let num = Math.random();
        if(num>0.5){
            resolve("success");
        }else{
            reject("fail");
        }
    },1000);
});

p.then(result=>{
    console.log('result :', result);
},err=>{
    console.log('err :', err);
})
复制代码

3.3.3 读取文件封装

const fs = require("fs");

function readFile(file){
    return new Promise((resolve,reject)=>{
        fs.readFile("file","utf8",(err,date)=>{
            if(err){
                reject(err);
            }else{
                resolve(date);
            }
        });
    });
}

readFile("a.txt").then(result=>{
    console.log('result :', result);
},err=>{
    console.log('err :', err);
})
复制代码

3.4 all和race方法

all:全部 race:竞赛

all和race都是Promise构造器对象的静态方法。直接使用Promise调用,以下:

  • Promise.all()
  • Promise.reace()
    • 返回值都是promise对象。

当有多个异步操做的时候,常常会有以下两种需求:(有点相似于运算符中的 逻辑与逻辑或

  1. 确保全部的异步操做完成以后,才进行某个操做,只要有一个失败,就不进行

  2. 只要有一个异步操做文章,就里面执行某个操做。

all使用以下

enter description here

若有错误,以下

enter description here

reac的用法

enter description here

4. 使用第三方的Promise库

针对第三方的promise库,有两个知名的库:

  • bluebird
  • q.js

以bluebird为例,在服务端演示其用法

第一步,安装

enter description here

第二步,使用

enter description here

4. 手写最完整版的promise原理

能够进入Github中更有层次的学习原理,本人在github中 逐步的封装了基础版promise,升级版promise,完整版的promise,

Github地址:github.com/quyuandong/…

示例

源码

// 定义当前promise的状态
const PENDING = 'PENDING'
const RESOLVED = 'RESOLVED'
const REJECTED = 'REJECTED'
//=================================================================
// promise对象
class Promise {
    constructor(exector) {

        // 初始化status为等待状态
        this.status = PENDING;
        // 成功的值
        this.value = undefined;
        // 失败的缘由
        this.reason = undefined;

        // 存储成功的回调函数
        this.onResolvedCallbacks = [];
        // 存储失败的回调函数
        this.onRejectedCallbacks = [];

        // 成功的处理函数
        let resolve = (value) => {
            if (this.status == PENDING) {
                this.value = value;     //存储成功的值
                this.status = RESOLVED; //将当前的状态修改成成功状态
                this.onResolvedCallbacks.forEach(fn => fn())
            }
        }

        // 失败的处理函数
        let reject = (reason) => {
            if (this.status == PENDING) {
                this.reason = reason;   //存储失败的缘由
                this.status = REJECTED; //将当前的状态修改成失败状态
                this.onRejectedCallbacks.forEach(fn => fn())
            }
        }

        // 当pormise抛出异常时
        try {
            exector(resolve, reject)    //当即执行函数
        } catch (e) {
            reject(e)
        }
    }

    /** * 参数: * @param {*} onFulfilled 失败状态 * @param {*} onRejected 成功状态 * * 说明: * promise的链式,能够一直.then下去,须要then返回一个promise * onFulfilled与onRejected的返回值,多是一个promise 也多是一个普通值 * 若是是promise,就采用它的状态 * 若是是普通值,这个值就做为下一个then成功的结果 * */
    then(onFulfilled, onRejected) {

        // 防止then中没有函数 p.then().then().then()...
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
        onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };

        /** * 建立一个promise,并返回一个promise,使得能够then能够进行链式调用 * settimeout做用: 使得该方法中,能够获取到promise2 * try做用: 处理onfulfilled可能抛出一个异常 */
        let promise2 = new Promise((resolve, reject) => {

            // 成功状态的处理方法-------同步操做(执行器中没有异步代码)
            if (this.status == RESOLVED) {
                setTimeout(() => {
                    try {
                        let x = onFulfilled(this.value);// x多是promise 也多是普通值
                        // 假如x是promise(有本身的状态),须要让pormise2拥有x一样的状态
                        resolvePromise(promise2, x, resolve, reject); // 处理promise2和x的关系
                    } catch (e) {
                        reject(e)
                    }
                }, 0);
            }

            // 失败状态的处理方法-------同步操做(执行器中没有异步代码)
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onRejected(this.reason)
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e)
                    }
                }, 0)
            }


            // 等待状态,将成功与失败的的操做进行保存-------同步操做(执行器中有异步代码)
            if (this.status === PENDING) {
                this.onResolvedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onFulfilled(this.value)
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                });

                this.onRejectedCallbacks.push(() => {
                    setTimeout(() => {
                        try {
                            let x = onRejected(this.reason)
                            resolvePromise(promise2, x, resolve, reject);
                        } catch (e) {
                            reject(e)
                        }
                    }, 0)
                })
            }

        })

        return promise2;
    }
}


//=================================================================
// 处理promise2和x的关系 ,x是onFulfilled或onRejected的返回值
function resolvePromise(promise2, x, resolve, reject) {

    // 若是 x === promise2,则是会形成循环引用,本身等待本身完成,则报“循环引用”错误
    if (promise2 === x) {
        return reject(new TypeError('my Chaining cycle detected for promise'))
    }

    // 防止屡次调用
    let called;

    // x是一个对象(不包含null)或是一个函数时
    if (x !== null && (typeof x === "object" || typeof x === "function")) {

        try {
            // 有可能x上会被手动地加上一个then属性
            let then = x.then;

            if (typeof then === 'function') {   // x是一个promise时

                // 至关于 x.then(y=>{},r=>{})
                then.call(x, y => {
                    if (called) return;
                    called = true;

                    // 递归,解决返回值里面扔是promise的问题
                    resolvePromise(promise2, y, resolve, reject)
                }, r => {
                    if (called) return;
                    called = true;

                    // 采用promise失败结果向下传递
                    reject(r)
                })
            } else {    // 此时x是一个对象,即返回的是一个对象
                resolve(x)
            }
        } catch (e) {   //当x抛出一个异常时
            if (called) return;
            reject(e)
        }
    } else {  //x 是一个普通的值
        resolve(x)
    }
}

//=================================================================
// resolve静态方法
Promise.resolve = function (val) {
    return new Promise((resolve, reject) => {
        resolve(val)
    });
}


//=================================================================
// reject静态方法
Promise.resolve = function (val) {
    return new Promise((resolve, reject) => {
        reject(val)
    });
}


//=================================================================
// race静态方法
Promise.race = function (promises) {
    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(resolve, reject)
        }
    });
}


//=================================================================
// all方法(获取全部的promise,都执行then,把结果放到数组,一块儿返回)
Promise.all = function (promises) {
    let arr = [];
    let y = 0;
    function processData(index, data) {
        arr[i] = data;
        y++;
        if (y == promises.length) {
            return arr;
        };
    };

    return new Promise((resolve, reject) => {
        for (let i = 0; i < promises.length; i++) {
            promises[i].then(data => {
                processData(i, data)
            }, reject)
        }
    })
}

//================================================================
// 
/** * 验证promise的正确性 * 1,先在后面加上下述代码 * 2,npm 有一个promises-aplus-tests插件 npm i promises-aplus-tests -g 能够全局安装 * 3,命令行 promises-aplus-tests [js文件名] 便可验证 */


// 目前是经过他测试 他会测试一个对象
// 语法糖
Promise.defer = Promise.deferred = function () {
    let dfd = {}
    dfd.promise = new Promise((resolve,reject)=>{
      dfd.resolve = resolve;
      dfd.reject = reject;
    });
    return dfd;
  }


//=================================================================
// 导出一个promise
module.exports = Promise;


/** * 注意:当在promise中出现异步的时候,必须先将then中成功和失败的回调函数 * 先进行保存,当promise中的状态发生改变的时候,才再进行执行 */
复制代码
相关文章
相关标签/搜索