promise

作者: FFriday | 来源:发表于2018-10-17 17:05 被阅读5次

    JavaScript所有代码都是单线程执行的,所以avaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现
    Js 的异步提高了程序的执行效率,同时也减少了程序的可读性。


    回调陷阱

    异步操作会在将来的某个时间点触发一个函数调用
    AJAX就是典型的异步操作

    es6 promise

    Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持。
    promiseA+规范中文 英文

    // promise用法
    new Promise(function (resolve, reject) {
        log('start new Promise...');
        var timeOut = Math.random() * 2;
        log('set timeout to: ' + timeOut + ' seconds.');
        setTimeout(function () {
            if (timeOut < 1) {
                log('call resolve()...');
                resolve('200 OK');
            }
            else {
                log('call reject()...');
                reject('timeout in ' + timeOut + ' seconds.');
            }
        }, timeOut * 1000);
    }).then(function (r) {
        log('Done: ' + r);
    }).catch(function (reason) {
        log('Failed: ' + reason);
    });
    
    // promise all
    var p1 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
    var p2 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 600, 'P2');
    });
    // 同时执行p1和p2,并在它们都完成后执行then:
    Promise.all([p1, p2]).then(function (results) {
        console.log(results); // 获得一个Array: ['P1', 'P2']
    });
    
    // promise race
    var p1 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 500, 'P1');
    });
    var p2 = new Promise(function (resolve, reject) {
        setTimeout(resolve, 600, 'P2');
    });
    Promise.race([p1, p2]).then(function (result) {
        console.log(result); // 'P1'
    });
    
    同步回调和异步回调
    // 同步回调
    var arr = [1,2,3];
    
    arr.forEach(function (x) {
      console.log('first');
    });
    
    console.log('last');
    
    // first first first
    // last
    
    // 异步回调
    setTimeout(function () {
      console.log('last')
    }, 1000);
    
    console.log('first');
    
    // first
    // last
    
    实现一个简单的promise

    promiseA+规范的内容

    • Promise 本质是一个状态机。每个 promise 只能是 3 种状态中的一种:pending、fulfilled 或 rejected。状态转变只能是 pending -> fulfilled 或者 pending -> rejected。状态转变不可逆。
    • then 方法可以被同一个 promise 调用多次。
    • then 方法必须返回一个 promise。规范里没有明确说明返回一个新的 promise 还是复用老的 promise(即 return this),大多数实现都是返回一个新的 promise,而且复用老的 promise 可能改变内部状态,这与规范也是相违背的。

    创建MyPromise类并根据规范初始化状态


    image.png

    promise的链式调用


    image.png
    实现一个
    const log = console.log;
    
    // 1.创建类
    class MyPromise {
        constructor(executor) {
            // 2.等待状态
            this.status = "pending";
            // 初始化data
            this.data = undefined;
            // 初始化reason
            this.reason = undefined;
            // 3.执行函数executor,定义我们的resolve,reject回调
            let resolve = (data) => {
                // log('resolve executor: '+ data);
                // 为了防止多次改变状态
                if(this.status === 'pending') { 
                   this.status = 'resolved'
                    this.data = data;
                    this.onFulFilledCallbacks.forEach((fn) => {
                       fn()
                    })
                }
            }
            let reject = (reason) => { 
               // 为了防止多次改变状态
                if(this.status === 'pending') {
                    this.status = 'rejected'
                    this.reason = reason;
                    this.onRejectedCallbacks.forEach((fn) => {
                       fn()
                    })
                }
            }
    
            // 5.储存fulfilled的回调
            this.onFulFilledCallbacks = [];
            this.onRejectedCallbacks = [];
    
            try {
                executor(resolve, reject);
            } catch(err) {
                reject(err);
            }
        }
        // 4. MyPromise原型上的then方法
        then (onFulFilled, onRejected) {
            // log('then executor');
            // 处理无参数时的问题(值穿透)
            onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : function(value) {return value};
            // 抛出错误直接丢到下一个then中
            onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
    
            let promise2;
            // 由于 promise.then 执行的时候promise对象已经是确定状态,从程序上说对回调函数进行同步调用也是行得通的。
            // 但是即使在调用 promise.then 注册回调函数的时候promise对象已经是确定的状态,
            // Promise也会以异步的方式调用该回调函数,这是在Promise设计上的规定方针。
    
            if(this.status === 'resolved'){
                promise2 = new MyPromise((resolve, reject) => {
                    setTimeout(() => {
                        try {
                            let x = onFulFilled(this.data);
                            // log('onFulFilled return  value : '+x)
                            resolvePromsie(promise2, x, resolve, reject);
                        } catch (err) {
                            reject(err);
                        }
                    }, 0);
                })
            }
            if(this.status === 'rejected'){
                promise2 = new MyPromise((resolve, reject) => {
                    setTimeout(() => {
                        try {
                            // If either onFulfilled or onRejected returns a value x,
                             // run the Promise Resolution Procedure [[Resolve]](promise2, x).
                            let x = onRejected(this.reason);
                            resolvePromsie(promise2, x, resolve, reject);
                        } catch (err) {
                            reject(err);
                        }
                    }, 0)
                })
            }
            if(this.status === 'pending'){
                // 这里要做一件很有意思的事。。。。
                promise2 = new MyPromise((resolve, reject) => {
                    // 将回调放在数组中等待调用
                    this.onFulFilledCallbacks.push(() => {
                        process.nextTick(() => {
                            try {
                                let x = onFulFilled(this.data);
                                resolvePromsie(promise2, x, resolve, reject);
                            } catch (err) {
                                reject(err);
                            }
                        })
                      })
                    this.onRejectedCallbacks.push(() => {
                        process.nextTick(() => {
                            try {
                                let x = onRejected(this.reason);
                                resolvePromsie(promise2, x, resolve, reject);
                            } catch (err) {
                                reject(err);
                            }     
                        });
                    })
                })
            }
            return promise2;
        }
        catch(onRejected){
            if(this.status === 'rejected'){
                promise2 = new MyPromise((resolve, reject) => {
                    setTimeout(() => {
                        try {
                            // If either onFulfilled or onRejected returns a value x,
                             // run the Promise Resolution Procedure [[Resolve]](promise2, x).
                            let x = onRejected(this.reason);
                            resolvePromsie(promise2, x, resolve, reject);
                        } catch (err) {
                            reject(err);
                        }
                    }, 0)
                })
            }
        }
        
    
    }
    
    
    function resolvePromsie(promise, x, resolve, reject){
            // 规范说先promise是不是来自同一个对象,并返回一个理由
            // If promise and x refer to the same object, reject promise with a TypeError as the reason.
            try {
                // If promise and x refer to the same object, reject promise with a TypeError as the reason.
                // 如果是相同引用就抛出错误
                // if(promise === x) return reject(new TypeError('不能循环引用'));
                // if x is an object or function,
                // 如果是对象,或是函数,我们就要看then是不是函数
                if(x != null && (typeof x === 'object' || typeof x === 'function')){
                    // Let then be x.then
                    let then = x.then;
                    if(typeof then === 'function'){
                        // If then is a function, call it with x as this,
                        // first argument resolvePromise, and second argument rejectPromise, where:
                        // 执行then函数,拿到返回值
                        then.call(x, y => {
                            resolvePromsie(promise, y, resolve, reject);
                        }, (err) => {
                            reject(err);
                        })
                    }else{
                        resolve(x);
                    }
                }else{
                    resolve(x);
                }
            } catch (err) {
                reject(err)
            }
        }
    
    
    
    var mypromise = new MyPromise((resolve,reject) => {
        resolve('第一个异步任务 OK');
        // let timeOut = Math.random()*2;
        // setTimeout(function () {
     //        if (timeOut < 1) {
     //            resolve('第一个异步任务 OK');
     //        }
     //        else {
     //            reject('第一个异步任务 reject');
     //        }
     //    }, timeOut * 1000);
    })
    var mypromise2 = new MyPromise((resolve,reject) => {
        resolve('第二个异步任务');
    })
    
    // 测试
    mypromise.then(function(data){
        log(data)
        return mypromise2;
    },function(error){
        log(error)
        return mypromise2;
    }).then().then().then(function(rd){
        log(rd);
       return 'test'
    }).then(function(val){
        log(val);
    }).then(function(val){
        log(val)
    });
    
    
    
    log('A'+111)
    setTimeout(()=>{
        log('setTimeout 0ms')
    })
    setTimeout(()=>{
        log('setTimeout 10ms')
    },10)
    

    相关文章

      网友评论

          本文标题:promise

          本文链接:https://www.haomeiwen.com/subject/mohhjftx.html