什么是Promise

中文理解为"承诺",指代在未来一段时间内会发生的事,比如JS中的一个定时器

setTimeout(function() {
    console.log(1); // 1
}, 1000);

上面的定时器在1秒之后会输出一个1。还比如Ajax请求,我们并不知道ajax何时会返回数据,但我们知道,数据一定会返回。
我们把定时器,ajax这些操作称为异步,一直以来我们获取异步返回的参数使用的大多是回调函数。promise的出现,是为了让我们放弃回调函数的写法,使代码变得更优雅,可读性更强。

Promise的简单用法

var fn = function() {};
var p = new Promise(fn);
var fn = function(resolve, reject) {};
var p = new Promise(fn);
var fn = function(resolve, reject) {};
var p = new Promise(fn);
p.then(function() {}, function() {});
var fn = function(resolve, reject) { resolve(); };
var p = new Promise(fn);
p.then(function() { console.log(1)}, function() { console.log(2)}); // 1

注意,fn中的两个参数执行互斥,意味着即使两个参数方法都被执行,也只会捕捉第一个,也就是写在前面的那一个

var fn = function(resolve, reject) { reject(); resolve(); };
var p = new Promise(fn);
p.then(function() { console.log(1)}, function() { console.log(2)}); // 2

上面因为reject写在前面,所以写在后面的resolve会被忽略,以至于then中只会执行第二个函数,输出2

var fn = function(resolve, reject) { resolve("我是参数"); };
var p = new Promise(fn);
p.then(function(data) { console.log(data)}, function(err) { console.log(err)}); // 我是参数

一般情况下,fn的第一个参数代表成功,第二个参数代表失败
then中的两个函数参数可以只写一个或都不写

var fn = function(resolve, reject) { resolve("我是参数"); };
var p = new Promise(fn);
p.then(function(data) { 
    return data;
}).then(function(data) {
    return data + 1;
}).then((data) => {
    return data + 2
});
// 我是参数12

Promise常用方法

var promise1 = Promise.resolve(3);
var promise2 = 42;
var promise3 = new Promise(function(resolve, reject) {
  setTimeout(resolve, 100, 'foo');
});

Promise.all([promise1, promise2, promise3]).then(function(values) {
  console.log(values);
});
// [3, 42, "foo"]
var promise1 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 500, 'one');
});

var promise2 = new Promise(function(resolve, reject) {
    setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then(function(value) {
  console.log(value);
});
// "two"
var promise1 = Promise.resolve(123);

promise1.then(function(value) {
  console.log(value);
}, function() { console.log( value)});
// 123
Promise.reject("Testing static reject").then(function(reason) {
  // 未被调用
}, function(reason) {
  console.log(reason); // "Testing static reject"
});

Promise代码实现原理

var fn = function(resolve, reject) { resolve("我是参数"); };
var p = new Promise(fn);
p.then(function(data) { 
    console.log(data);
});
// 我是参数
// 首先创建一个Promise构造函数
function Promise() {
}
// 因为每个Promise实例都存在一个then方法,所以在Promise的原型prototype上加入then
Promise.prototype.then = function() {
}

根据promise的创建方式 new Promise(function(resolve, reject) { });可以知道,构造函数接收一个函数executor作为参数

function Promise(executor) {

}

Promise创建时传入的函数会直接执行,所以:executor需直接执行,并传入两个函数resolve和reject

function Promise(executor) {
  function resolve() {

  }
  function reject() {

  }
  executor(resolve, reject)
}

Promise有三种状态,1、pending(等待),2、resolved(成功),3、rejected(失败),默认为pendding,当构造函数中的resolve方法被执行,Promise置为resolved,当构造函数中的reject方法被执行,Promise置为rejected,
resolved 和 rejected只能存在一种,所以只有当状态为pending的时候才会改变

function Promise(executor) {
  let that = this;
  that.status = 'pending';
  function resolve() {
    if(that.status === 'pending'){
      that.status = 'resolved';
    }
  }
  function reject() {
    that.status = 'rejected';
      if(that.status === 'pending'){
          that.status = 'rejected';
      }
  }
  executor(resolve, reject)
}

then 方法可以接收两个函数作为参数

Promise.prototype.then(onFilfulled,onRejected) {

}

因为then为异步执行,这里使用两个成员变量,分别存储成功所有的成功(onFilFulledCallbacks)和所有的失败(onRejectedCallbacks), 当构造Promise为resolved状态时,成功函数执行,当Promise为rejected时,失败函数开始执行,

function Promise(executor) {
  let that = this;
  that.status = 'pending';
  // 声明成功函数的存储空间
  that.onFilFulledCallbacks = [];
  // 声明失败函数的存储空间
  that.onRejectedCallbacks = [];
  function resolve() {
    if(that.status === 'pending'){
      that.status = 'resolved';
      // 执行成功函数
      that.onFilFulledCallbacks.forEach((fn)=>{
          fn();
      });
    }
  }
  function reject() {
    that.status = 'rejected';
      if(that.status === 'pending'){
          that.status = 'rejected';
          // 执行失败的函数
          that.onRejectedCallbacks.forEach((fn)=>{
              fn();
          });
      }
  }
  executor(resolve, reject)
}


Promise.prototype.then(onFilfulled,onRejected) {
  var that = this;
  if (that.status === 'pending') {
    that.onFilFulledCallbacks.push(onFilfulled);
    that.onRejectedCallbacks.push(onRejected);
  }
  if (this.status === 'resolved') {
    onFilfulled();
  }
  if (that.status === 'rejected') {
    onRejected();
  }
}

由于Promise构造函数中,resolve,和reject的执行结果会传递给then中的回调,如下:

const p = new Promise(function(resolve, reject) {
  resolve('传入一个值');
})
p.then(function(value) {
  console.log(value); // 传入一个值
})

所以我们在构造函数中定义一个value来接收resolve或reject的值,然后再then中执行onFilfulled或onRejected时返回

function Promise(executor) {
  let that = this;
  that.status = 'pending';
  that.value = null;
  // 声明成功函数的存储空间
  that.onFilFulledCallbacks = [];
  // 声明失败函数的存储空间
  that.onRejectedCallbacks = [];
  function resolve(value) {
    if(that.status === 'pending'){
      that.status = 'resolved';
      that.value = value;
      // 执行成功函数
      that.onFilFulledCallbacks.forEach((fn)=>{
          fn();
      });
    }
  }
  function reject(value) {
    that.status = 'rejected';
      if(that.status === 'pending'){
          that.status = 'rejected';
          that.value = value;
          // 执行失败的函数
          that.onRejectedCallbacks.forEach((fn)=>{
              fn();
          });
      }
  }
  executor(resolve, reject)
}

Promise.prototype.then(onFilfulled,onRejected) {
  var that = this;
  if (that.status === 'pending') {
    that.onFilFulledCallbacks.push(function() {
      onFilfulled(that.value); // 执行时返回
    });
    that.onRejectedCallbacks.push(function() {
      onRejected(that.value);  // 执行时返回
    });
  }
  if (this.status === 'resolved') {
    onFilfulled(that.value); // 执行时返回
  }
  if (that.status === 'rejected') {
    onRejected(that.value); // 执行时返回
  }
}

由于promise实例可以链式书写多个then方法,所以then中应该返回一个新的promise

Promise.prototype.then(onFilfulled,onRejected) {
  var that = this;
  // 返回promise
  return new Promise(function(resolve, reject) {
    if (that.status === 'pending') {
      that.onFilFulledCallbacks.push(function() {
        onFilfulled(that.value);
      });
      that.onRejectedCallbacks.push(function() {
        onRejected(that.value);
      });
    }
    if (this.status === 'resolved') {
      onFilfulled(that.value);
    }
    if (that.status === 'rejected') {
      onRejected(that.value);
    }
  });
}

如果Promise执行中,出现错误则执行reject,这里引入try catch

function Promise(executor) {
  try{
    executor(resolve,reject);
  }catch(e){
    reject(e);
  }
}

多个then链式调用时,前一个then中返回的值会传入到后一个then中,需要判断then中返回的值类型

// 判断then返回值的关系类型, promise2, 为 then中返回的promise,promise3为then中回调函数的执行结果,resolve,reject为Promise的resolve,reject;
function resolvePromiseRelation(promise2,promise3,resolve,reject){

}

改造then方法

Promise.prototype.then(onFilfulled,onRejected) {
  // 如果onFilfulled或onRejected不存在,添加默认函数
  onFilfulled = typeof onFilfulled === 'function'? onFilfulled : function(value) { return value; };
  onRejected = typeof onRejected === 'function'?onRejected : function(err) { throw err; };
  var that = this;
  // 返回promise
  const promise2 = new Promise(function(resolve, reject) {
    if (this.status === 'resolved') {
      const promise3 = onFilfulled(that.value);
      resolvePromiseRelation(promise2,promise3,resolve,reject);
    }
    if (that.status === 'rejected') {
      const promise3 = onRejected(that.value);
      resolvePromiseRelation(promise2,promise3,resolve,reject);
    }
    if (that.status === 'pending') {
      that.onFilFulledCallbacks.push(function() {
        let promise3 = onFilfulled(that.value);
        resolvePromiseRelation(promise2,promise3,resolve,reject);
      });
      that.onRejectedCallbacks.push(function() {
        let promise3 = onRejected(that.reason);
        resolvePromiseRelation(promise2,promise3,resolve,reject);
      });
    }
  });
  return promise2;
}

因为promise2的使用在自己的创建中,所以我们引入定时器,异步获取promise2

Promise.prototype.then = function(onFilfulled,onRejected){
    onFilfulled = typeof onFilfulled === 'function'?onFilfulled:value=>value;
    onRejected = typeof onRejected === 'function'?onRejected:err=>{throw err};
    let that = this;
    let promise2 = new Promise((resolve,reject)=>{
        if(that.status === 'resolved'){
            setTimeout(()=>{
                try{
                    let promise3 = onFilfulled(that.value);
                    resolvePromiseRelation(promise2,promise3,resolve,reject);
                }catch(e){
                    reject(e);
                }
            },0);
        }
        if(that.status === 'rejected'){
            setTimeout(()=>{
                try{
                    let promise3 = onRejected(that.reason);
                    resolvePromiseRelation(promise2,promise3,resolve,reject);
                }catch(e){
                    reject(e);
                }
            },0);
        }
        if(that.status === 'pending'){
            that.onFilFulledCallbacks.push(function(){
                setTimeout(()=>{
                    try{
                        let promise3 = onFilfulled(that.value);
                        resolvePromiseRelation(promise2,promise3,resolve,reject);
                    }catch(e){
                        reject(e);
                    }
                },0);
            });
            that.onRejectedCallbacks.push(function(){
                setTimeout(()=>{
                   try{
                       let promise3 = onRejected(that.reason);
                       resolvePromiseRelation(promise2,promise3,resolve,reject);
                   }catch(e){
                       reject(e);
                   }
               },0);
           });
        }
    });
    return promise2;
}

梳理resolvePromiseRelation函数中promise2和promise3的关系

function resolvePromiseRelation(promise2,promise3,resolve,reject){
    // 判断是否循环引用
    if(promise2 === promise3){
        return reject(new TypeError('循环引用了!'));
    }
    // 表示当前有没有被调用过,预防与其它人写的promise混合使用时,对方的resolve和reject都被调用,用变量限制。
    let called;
    // 如果promise3是一个对象, 则需要判断promise3是不是一个promise,如果是,继续判断,如果不是,代表promise3是一个基本类型,直接resolve即可
    if(promise3 !==null && (typeof promise3 === 'object' || typeof promise3 === 'function')) {
        try{
            // 取出promise3的then方法。
            let then = promise3.then;
            if(typeof then === 'function'){
                // 执行then方法获取到返回值,再次判断两个promise的关系,递归
                then.call(promise3, (promise4)=>{
                    if(called) return;
                    called = true;
                    resolvePromiseRelation(promise2,promise4,resolve,reject);
                },(r)=>{
                    if(called) return;
                    called = true;
                    reject(r);
                });
            }else{
                resolve(promise3);
            }
        }catch(e){
            if(called) return;
            called = true;
            reject(e);
        };
    } else {
        resolve(promise3);
    }
}

至此promise基本功能已经完成,代码如下

function Promise(executor){
    let that = this;
    that.status = 'pending';
    that.value = null;
    that.reason = null;
    that.onFilFulledCallbacks = [];
    that.onRejectedCallbacks = [];

    function resolve(value){
        if(that.status === 'pending'){
            that.status = 'resolved';
            that.value = value;
            that.onFilFulledCallbacks.forEach((fn)=>{
                fn();
            });
        }
    }
    function reject(reason){
        if(that.status === 'pending'){
            that.status = 'rejected';
            that.reason = reason;
            that.onRejectedCallbacks.forEach((fn)=>{
                fn();
            });
        }
    }
    try{
        executor(resolve,reject);
    }catch(e){
        reject(e);
    }
}

Promise.prototype.then = function(onFilfulled,onRejected){
    onFilfulled = typeof onFilfulled === 'function'?onFilfulled:value=>value;
    onRejected = typeof onRejected === 'function'?onRejected:err=>{throw err};
    let that = this;
    let promise2 = new Promise((resolve,reject)=>{
        if(that.status === 'resolved'){
            setTimeout(()=>{
                try{
                    let promise3 = onFilfulled(that.value);
                    resolvePromiseRelation(promise2,promise3,resolve,reject);
                }catch(e){
                    reject(e);
                }
            },0);
        }
        if(that.status === 'rejected'){
            setTimeout(()=>{
                try{
                    let promise3 = onRejected(that.reason);
                    resolvePromiseRelation(promise2,promise3,resolve,reject);
                }catch(e){
                    reject(e);
                }
            },0);
        }
        if(that.status === 'pending'){
            that.onFilFulledCallbacks.push(function(){
                setTimeout(()=>{
                    try{
                        let promise3 = onFilfulled(that.value);
                        resolvePromiseRelation(promise2,promise3,resolve,reject);
                    }catch(e){
                        reject(e);
                    }
                },0);
            });
            that.onRejectedCallbacks.push(function(){
                setTimeout(()=>{
                   try{
                       let promise3 = onRejected(that.reason);
                       resolvePromiseRelation(promise2,promise3,resolve,reject);
                   }catch(e){
                       reject(e);
                   }
               },0);
           });
        }
    });
    return promise2;
}

function resolvePromiseRelation(promise2,promise3,resolve,reject){
    if(promise2 == promise3){
        return reject(new TypeError('循环引用了!'));
    }
    let called;
    if(promise3!==null&&(typeof promise3 === 'object' || typeof promise3 === 'function')){
        try{
            let then = promise3.then;
            if(typeof then === 'function'){
                then.call(promise3, (promise4)=>{
                    if(called) return;
                    called = true;
                    resolvePromiseRelation(promise2,promise4,resolve,reject);
                },(r)=>{
                    if(called) return;
                    called = true;
                    reject(r);
                });
            }else{
                resolve(promise3);
            }
        }catch(e){
            if(called) return;
            called = true;
            reject(e);
        };
    }else{
        resolve(promise3);
    }
}

Promise.prototype.catch = function(errFn){
    return this.then(null,errFn);
}
Promise.prototype.finally = function(fn){
    this.then(()=>{
        fn();
    },()=>{
        fn();
    });
    return this;
}

Promise静态方法

// 使用
const a = new Promise(function(resolve) {
  resolve('第一个')
});
const b = new Promise(function(resolve) {
  resolve('第二个')
});
Promise.all([a, b]).then(function(values) {
  console.log(values); // ['第一个', '第二个']
})

代码实现

Promise.all = function(values){ // 传入一个promise的数组
    // 返回一个promise对象
    return new Promise((resolve,reject)=>{
        // 存储每个参数promise对象的执行结果
        let results = [];
        // 记录promise执行完成的个数
        let index = 0;
        // 定义函数,处理promise执行结果,放入results中,并让index累加
        function addToArr(key,value){
            index++;
            results[key] = value;
            // 当index等于传入promise的个数时,表示所有执行完成,运行返回的Promise对象的resolve
            if(index === values.length){
                resolve(results);
            }
        }

        for(let i = 0; i < values.length; i++){
            let current = values[i];
            // 如果传入的是promise对象
            if(current && current.then && typeof current.then === 'function'){
                current.then((value)=>{
                    addToArr(i,value);
                },reject);
            }else{ // 否则传入的是普通对象
                addToArr(i,current);
            }
        }
    });
}

代码实现如下

Promise.race = function(values){
    return new Promise((resolve,reject)=>{
        for(let i = 0; i < values.length; i++){ // 循环判断传入的values
            let current = values[i];
            if(current&&current.then&&typeof current.then === 'function'){ // 如果是promise对象,则替换promise的resolve和reject
                current.then(resolve,reject);
            }else{ // 基本类型直接返回
                resolve(current);
            }
        }
    });
}
Promise.resolve('成功').then(function(value) {
  console.log(value);
})
// 成功

代码实现

Promise.resolve = function(value){
    return new Promise((resolve,reject)=>{
        resolve(value);
    });
}
Promise.reject('失败').then(function(value) {
  console.log(value); // 不执行
}, function(err) {
  console.log(err); // 执行
})
// 失败

代码实现

Promise.reject = function(reason){
    return new Promise((resolve,reject)=>{
        reject(reason);
    });
}
Promise.defer = Promise.deferred = function(){
    let dfd = {};
    dfd.promise = new Promise((resolve, reject)=>{
        dfd.resolve = resolve;
        dfd.reject = reject;
    });
    return dfd;
}

至此,Promise已经完成,下面为扩展部分

扩展部分

bluebird

蓝鸟, promise的库,在node中使用,实现将异步方法变为同步

npm install bluebird;
const fs = require('fs');
const bluebird = require('bluebird');
// 将异步方法变为同步,将回调函数改为then调用
const readFile = bluebird.promisify(fs.readFile);
// 可以实现如下使用方式
Promise.all([readFile('./name1.txt'), readFile('./name2.txt')]);

实现原理

function promisify(fn) { // node中的util模块自带了这个功能
    return function(...args) { // 返回值是一个函数
        return new Promise(function(resolve, reject) { // 返回一个promise
            fn(...args, function(err, data) {
                if (err) {
                    reject(err);
                } else {
                    resolve(data);
                }
            });
        })
    }
}

node中的mz模块

mz中的fs模块完全是封装好的promisify方法

// npm install mz;
const fs = require('mz/fs');
Promise.all([fs.readFile('./name1.txt'), fs.readFile('./name2.txt')]);

总结

generator

生成器 生成迭代器

function fns() {
    const obj = {0: 1, 1: 2, 2: 3, [Symbol.iterator]: function() {
        let index = 0;
        const self = this;
        return {
            next() {
                return { value: self[index], done: index++ === self.length };
            }
        }
    }}
}

function * read() { // generator函数, 返回一个迭代器
    return 100;
}
const r = read();
console.log(r.next()); // { value: 100, done: true }

一般generator会配合yield使用

function * read() {
    yield 1;
    yield 2;
    return 100;
}
const it = read();
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 100, done: true }