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 像一个不会产生返回值的中间器。

原文地址:https://www.cnblogs.com/coding4/p/6079937.html