• promise的学习


    为了解决回调地狱的问题,所以出现了promise的设计思想。

    #### promise A+ 规范
    [https://promisesaplus.com/](https://promisesaplus.com/)
    #### 几点需要强调的。
    - promise 必须有一个then方法。
    - promise 必须有三个状态。"PENDING" "FULFILLED" "REJECTED" 。状态一旦改变,不可回滚。
    - promise 可以链式调用。promise 可以穿透(不写resolve方法或者是一个常量也行)。
    - promise 返回一个新的promise。
    - 捕获错误机制。找不到就向下找。

    #### 手写一个promise的思路。总体就是数组保存所有的then里注册的函数。然后等时机到了一个个执行。

    (1) 先有一个类,有then方法。status有三个变量pending,fulfilled,rejected。
    (2) 成功的变量value和失败的变量reason,保存成功回调onResolvedCallbacks,保存失败的回调onRejectedCallbacks
    (3) 主体是then函数的递归,链式调用所有then返回一个promise。但是为了解决then函数的返回普通值和then穿透的问题。

    #### 如何证明promise和x重复的问题。

    #####   resolvePromise 中的 called 表示害怕有的人的promise写的不规范,resolve之后还能reject,所以加了called进行了限制。

    const PENDING = "PENDING";
    const SUCCESS = "FULFILLED";
    const FAIL = "REJECTED";
    // 严谨 应该判断 别人的promise 如果失败了就不能在调用成功 如果成功了不能在调用失败
    function resolvePromise(promise2, x,resolve,reject) { 
        if(promise2 === x){
           return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>'));
        }
        let called;
        if(typeof x === 'function' || (typeof x === 'object' && x != null)){
          try{
            let then = x.then;  // then 可能是getter object.defineProperty
            if(typeof then === 'function'){  // {then:null}
               then.call(x,y=>{ 
                 if(called) return; // 1)
                 called = true;
                  resolvePromise(promise2,y,resolve,reject); 
               },r=>{
                 if(called) return; // 2)
                 called = true;
                  reject(r);
               }) 
            }else{ 
              resolve(x);
            }
          }catch(e){
            if(called) return; // 3) 为了辨别这个promise 不能调用多次
            called = true;
            reject(e);
          }
        }else{
          resolve(x);
        }
    }
    class Promise {
      constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        const resolve = value => {
          if (this.status === PENDING) {
            this.value = value;
            this.status = SUCCESS;
            this.onResolvedCallbacks.forEach(fn => fn());
          }
        };
        const reject = reason => {
          if (this.status === PENDING) {
            this.reason = reason;
            this.status = FAIL;
            this.onRejectedCallbacks.forEach(fn => fn());
          }
        };
        try {
          executor(resolve, reject);
        } catch (e) {
          reject(e);
        }
      }
      then(onFulfilled, onRejected) { // .catch(function(){}) .then(null,function)
      onFulfilled = typeof onFulfilled === 'function'?onFulfilled:val=>val;
      onRejected =  typeof onRejected === 'function'?onRejected:err=>{throw err}
        let promise2;
        promise2 = new Promise((resolve, reject) => {
          if (this.status === SUCCESS) {
            setTimeout(() => {
              try {
                let x = onFulfilled(this.value);
                resolvePromise(promise2, x, resolve, reject);
              } catch (err) {
                reject(err);
              }
            });
          }
          if (this.status === FAIL) {
            setTimeout(() => {
              try {
                let x = onRejected(this.reason);
                resolvePromise(promise2, x, resolve, reject);
              } catch (err) {
                reject(err);
              }
            });
          }
          if (this.status === PENDING) {
            this.onResolvedCallbacks.push(()=>{
              setTimeout(() => {
                try {
                  let x = onFulfilled(this.value);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (err) {
                  reject(err);
                }
              });
            });
            this.onRejectedCallbacks.push(()=> {
              setTimeout(() => {
                try {
                  let x = onRejected(this.reason);
                  resolvePromise(promise2, x, resolve, reject);
                } catch (err) {
                  reject(err);
                }
              });
            });
          }
        });
        return promise2;
      }
    }
    // 希望测试一下这个库是否符合我们的promise A+规范
    // promises-aplus-tests
    Promise.defer = Promise.deferred = function(){
      let dfd = {};
      dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
      });
      return dfd;
    }
    module.exports = Promise;
    // npm i promises-aplus-tests -g
    
    // promise 相关方法
    // generator
    

      

      

    promise的三种状态:

      • pending 等待状态
      • resolved 完成状态
      • rejected 拒绝状态

    promise的三种状态,只能是pending->resolved或者pending->rejected,不能有其他类型的状态转换,并且状态一旦发生转换,就不再发生变化。

    promise的方法:

    1.then

    2.all

    3.race

    上例子吧 :

    例子1:在异步的读取完a1,a2,a3,a4,a5的文件之后,执行一个总的方法。

     1 'use strict';
     2 //这是一个简单的应用
     3 //要求:在异步读完a1.txt,a2.txt,a3.txt,a4.txt的时候执行一个总的方法
     4 var  Promise = require('bluebird');
     5 var fs = require("fs") ;
     6 
     7 
     8 var promises = [];
     9 
    10 //Promise all方法的使用
    11 for(var i = 1; i < 5; i++){
    12     var promise = new Promise(function(resolve,reject){
    13         fs.readFile("a" + i + ".txt","utf8",function (error,data){
    14             if(error){
    15                 reject(error)
    16             }else{
    17                 resolve(data)
    18             }
    19         }) ;
    20     });
    21     promises.push(promise);
    22 }
    23 
    24 Promise.all(promises).then(function(data){
    25     console.log(data);
    26 }).catch(function(e){
    27     console.log(e);
    28 });
    //

    [ 'this is a1 !', 'this is a2 !', 'this is a3 !', 'this is a4 !' ]

    例子2:在异步的读取a1,a2,a3,a4,a5的文件之后,只要有一个文件读取完成,就执行最后的方法。

     1 "use strict";
     2 
     3 var Promise = require("bluebird");
     4 var fs = require("fs");
     5 
     6 var promises = [];
     7 
     8 //Promise race方法的使用
     9 for(var i = 1; i < 5; i++){
    10     var promise = new Promise(function(resolve,reject){
    11         fs.readFile("a" + i + ".txt","utf8",function (error,data){
    12             if(error){
    13                 reject(error)
    14             }else{
    15                 resolve(data)
    16             }
    17         }) ;
    18     });
    19     promises.push(promise);
    20 }
    21 Promise.race(promises).then(function(data){
    22   console.log(data);
    23 }).catch(function(e){
    24   console.log(e);
    25 })
    //this is a1 !

    例子3:要求:在读完a1.txt的时候读a2.txt,在读完a2.txt,读a3,然后a4.

     1 var a1 = new Promise(function(resolve,reject){
     2     fs.readFile('a1.txt','utf8',function(error,data){
     3         if(error){
     4             reject(error);
     5         }else{
     6             resolve(data);
     7         }
     8     });
     9 });
    10 var ss = a1.then(function(){
    11     return new Promise(function(resolve,reject){
    12         fs.readFile('a2.txt','utf8',function(error,data){
    13             if(error){
    14                 reject(error);
    15             }else{
    16                 resolve(data);
    17             }
    18         });
    19     });
    20 }).then(function(){
    21     return 'yanjinyun';
    22     /*return new Promise(function(resolve,reject){
    23         fs.readFile('a3.txt','utf8',function(error,data){
    24             if(error){
    25                 reject(error);
    26             }else{
    27                 resolve(data);
    28             }
    29         });
    30     });*/
    31 }).then(function(data){
    32     return new Promise(function(resolve,reject){
    33         fs.readFile('a4.txt','utf8',function(error,data){
    34             if(error){
    35                 reject(error);
    36             }else{
    37                 resolve(data);
    38             }
    39         });
    40     });
    41 }).catch(function(e){
    42 
    43 });

    #### 第一层的then和第二层的then

    let aaa = new Promise(function(resolve, reject) {
        setTimeout(() => {
            resolve(132)
        },100)
    });
    aaa.then(data => {
        console.log('--->>>>1', data)
        return 'then1'
    }).then(data => {
        console.log('--->>>>3', data)
        return 'then3'
    });
    aaa.then(data => {
        console.log('--->>>>2', data)
    });
    
    // 结果 
    --->>>>1 132
    --->>>>2 132
    --->>>>3 then1
    

      

    #### new Promise的时候promise里边的就执行了。

    #### then如果不返回一个值的,默认返回undefined,算一个普通值。

    let aaa = new Promise(function(resolve, reject) {
        setTimeout(() => {
            resolve(132)
        },100)
    });
    aaa.then(data => {
        console.log('--->>>>1', data)
    }).then(data => {
        console.log('--->>>>3', data)
        return 'then3'
    });
    aaa.then(data => {
        console.log('--->>>>2', data)
    });

    --->>>>1 132
    --->>>>2 132
    --->>>>3 undefined


    #### 只要有一个reject函数。后边的继续resolve。除非这个reject函数 报错。才会被catch到。

    let aaa = new Promise(function(resolve, reject) {
        setTimeout(() => {
            resolve(132)
        },100)
    });
    aaa.then(data => {
        console.log('--->>>>1', data)
        throw new Error();
    }, err => {
        console.log('进入---err1')
        return 'err1';
    }).then(data => {
        console.log('--->>>>3', data)
    }, err => {
        console.log('进入---err3')
        // return 'err3'; // 写return 和 不写 return的区别在于 下边的resolve中接收到的值是不是undefined
        throw new Error();
    }).then(data => {
        console.log('--->>>>4', data)
    }, err => {
        console.log('进入---err4')
        return 'err4';
    }).then(data => {
        console.log('--->>>>5', data)
    }, err => {
        console.log('进入---err5')
        return 'err5';
    }).catch(e => {
        console.log(e + '---');
    });
    aaa.then(data => {
        console.log('--->>>>2', data)
    });
    
    --->>>>1 132
    --->>>>2 132
    进入---err3
    进入---err4
    --->>>>5 err4
     
     

    #### resolve(new Error('error')) 结果也是正常执行的。

    ##### promise的defer实现。

    Promise.defer = Promise.deferred = function(){
      let dfd = {};
      dfd.promise = new Promise((resolve,reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
      });
      return dfd;
    }
    // 没用defer之前
    function read(url) {
    	return new Promise((resolve, reject) => {
    		fs.readFile(url, 'utf-8', (err, data) => {
    			if(err) reject(err);
    			resolve(data);
    		})
    	})
    }
    
    // 用了defer之后
    function read(url) {
    	let defer = Promise.defer();
    	fs.readFile(url, 'utf-8', (err, data) => {
    		if(err) defer.reject(err);
    		defer.resolve(data);
    	})
    	return defer.promise;
    }
    

      

    #### race 只要有一个失败了就失败了

    // 测试只要有一个race 中只要有一个promise reject了,那么久reject了。
    let aa = () => {
        return new Promise(function(resolve, reject) {
            setTimeout(() => {
                reject(1);
            },1000)
        })
    }
    
    let bb = () => {
        return new Promise(function(resolve, reject) {
            setTimeout(() => {
                resolve(2);
            },2000)
        })
    }
    Promise.race([aa(), bb()]).then(data => {
        console.log(data);
    }).catch(e => {
        console.log('e', e);
    })

    //
    e 1
    
    

     #### generator

    ### promisify 的用法

    function promisify(fn){ // node中 util模块自带了这个功能
        return function(...args){ // args = [name,'utf8']
            return new Promise((resolve,reject)=>{
                fn(...args,function(err,data){
                    if(err) reject(err);
                    resolve(data);
                }); // fs.readFile('name.txt','utf8);
            })
        }
    }
    // let readFile = promisify(fs.readFile);
    Promise.all([1,fs.readFile('./name.txt','utf8'),fs.readFile('./age.txt','utf8')]).then(data=>{
       return 100
    },err=>{
        console.log(err);
    }).then(data=>{
    });
    

      

    #### promise 的  finally 

    - 无论前边是catch还是finally都是执行。

    - 只要前边的catch捕获到了错误,后边的then仍然会执行。后边的then的值是catch的返回值。

    - finally 并不会捕获错误,如果发生错误finally前边没有捕获的话,finally仍然会执行,后边的catch仍然会去捕获。

    - finallly 像一个不会产生返回值的中间器。

  • 相关阅读:
    配置Yaf
    计算机科学中最重要的32个算法
    mysql show status详解
    Structs 在Struts.xml中配置action时,action的name属性最好首字母大写
    MyEclipse创建ssh项目和连接数据库
    Myeclipse安装svn插件
    win7安装ubuntu双系统
    Java查看API和源码的方法
    华为oj平台的新网址
    详细解析Java中抽象类和接口的区别
  • 原文地址:https://www.cnblogs.com/coding4/p/6079937.html
Copyright © 2020-2023  润新知