Skip to content

Promise 学习笔记

第一章:走进 Promise 世界

一、为什么会出现 Promise?

在 JavaScript 中,异步操作包括但不限于网络请求、定时器、读取文件、数据库操作等。这些操作可能需要一段时间才能完成,并且通常会在其它代码执行的同时进行。

在 Promise 出现之前,JavaScript 开发者通常使用回调函数(callback)来处理异步操作。然而,当多个异步操作需要按照特定的顺序执行或同时执行时,使用回调函数往往会导致代码难以阅读和维护,这种情况通常被称为"回调地狱"(callback hell)。

回调地狱:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件。

举个例子

在实际的使用中,有非常多的应用场景我们不能立即知道应该如何继续往下执行。最常见的一个场景就是 ajax 请求,通俗来说,由于网速的不同,可能你得到返回值的时间也是不同的,这个时候我们就需要等待,结果出来了之后才知道怎么样继续下去。

javascript
let xhr = new XMLHttpRequest();
xhr.open('get', 'https://xxx/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC');
xhr.send();
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
            console.log(xhr.responseText)
        }
    }
}

在 ajax 的原生实现中,利用了 onreadystatechange 事件,当该事件触发并且符合一定条件时,才能拿到想要的数据,之后才能开始处理数据,这样做看上去并没有什么麻烦,但如果这个时候,我们还需要另外一个 ajax 请求,这个新 ajax 请求的其中一个参数,得从上一个 ajax 请求中获取,这个时候我们就不得不等待上一个接口请求完成之后,再请求后一个接口。

javascript
let xhr = new XMLHttpRequest();
xhr.open('get', 'https://xxx/api?unescape=1&version=v61&appid=82294778&appsecret=4PKVFula&city=%E5%8C%97%E4%BA%AC');
xhr.send();
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4) {
        if (xhr.status >= 200 && xhr.status < 300) {
            console.log(xhr.responseText)
            
            // 伪代码....
            let xhr = new XMLHttpRequest();
            xhr.open('get','http://www.xx.com?a'+xhr.responseText);
            xhr.send();
            xhr.onreadystatechange = function(){
                if(xhr.readyState === 4){
                    if(xhr.status>=200 && xhr.status<300){
                        console.log(xhr.responseText)
                        
                    }
                }
            }
        }
    }
}

当出现第三个 ajax(甚至更多)仍然依赖上一个请求时,我们的代码就变成了一场灾难。这场灾难,往往也被称为回调地狱

因此我们需要一个叫做 Promise 的东西,来解决这个问题,当然,除了回调地狱之外,还有个非常重要的需求就是为了代码更加具有可读性和可维护性,我们需要将数据请求与数据处理明确的区分开来

二、Promise 是什么?

Promise 是在 ECMAScript 6(ES6,也称为 ECMAScript 2015)中引入的。ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象。指定回调函数的方式也变得更加灵活易懂,也解决了异步回调地狱的问题。

Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数)更合理、更强大。抛弃了旧方案是单纯使用回调函数。

从语法上说,Promise 是一个构造函数;从功能上说,Promise 对象用来封装一个异步操作并可以获取其成功 / 失败的结果值。

Promise 是 JavaScript 中处理异步操作的一种方式。 Promise 是 JavaScript 中用于处理异步操作的一个对象(构造函数)。

三、都要学习哪些内容?

  1. Promise 的基本概念:理解 Promise 是什么,以及为什么需要 Promise。理解 Promise 的三种状态(pending、fulfilled 和 rejected)以及这些状态的含义。

  2. 创建 Promise:学习如何创建一个新的 Promise 对象,以及如何在异步操作完成时改变 Promise 的状态(使用 resolvereject 函数)。

  3. 使用 Promise:学习如何使用 .then() 方法处理 fulfilled 状态的 Promise,以及如何使用 .catch() 方法处理 rejected 状态的 Promise。

  4. 链式调用:理解 Promise 的链式调用机制,以及如何通过链式调用组织多个异步操作。

  5. 错误处理:理解如何在 Promise 链中正确地处理错误,并学习关于错误冒泡和拦截的规则。

  6. 并行执行和竞态条件:学习如何使用 Promise.all()Promise.race() 方法并行执行多个异步操作,并理解这两个方法的区别。

  7. 其他静态方法:了解其他有用的 Promise 静态方法,例如 Promise.resolve()Promise.reject()

  8. 实际应用:通过实际编程练习来应用你所学的知识,例如使用 Promise 封装一个 AJAX 请求,或者将回调函数式的 API 转换为返回 Promise 的 API。

  9. Async/Await:在熟悉了 Promise 后,可以进一步学习 ES2017 引入的 async/await 语法,它是基于 Promise 的异步编程模型,提供了更直观、更简洁的语法。

四、使用 Promise 的好处?

1)链式调用:Promise 可以通过 .then() 方法进行链式调用,使得多个异步操作按照特定的顺序执行变得更加简单。

2)错误处理:Promise 通过 .catch() 方法提供了一种统一的错误处理机制。

3)并行执行:Promise.all()Promise.race() 方法允许我们并行执行多个异步操作,并在所有操作都完成后或第一个操作完成后得到结果。

4)改善代码可读性:相比于回调函数,Promise 的链式调用方式使得代码更加清晰和易于理解。

五. 初体验

创建 promise 对象(pending 状态)。

javascript
const p = new Promise(executor);

解释:

当创建一个 Promise 对象时,需要提供一个 executor 函数作为参数。这个 executor 函数接收两个参数:resolvereject,它们都是函数。

  • resolve 函数:当异步操作成功完成时,应该调用这个函数,并将结果作为参数传递。这将导致 Promise 对象的状态变为 fulfilled(已完成),并将结果值设置为传递给 resolve 的值。
  • reject 函数:当异步操作失败时,应该调用这个函数,并将错误或失败原因作为参数传递。这将导致 Promise 对象的状态变为 rejected(已拒绝),并将原因设置为传递给 reject 的值。

executor 函数会在 Promise 对象创建后立即同步执行。应该在这个函数中启动异步操作。当异步操作完成时,应该调用 resolvereject 来更新 Promise 的状态和值。

javascript
const p = new Promise((resolve, reject) => {
  // 异步操作
  setTimeout(() => {
    if (/* 操作成功 */) {
      // 调用 resolve(data),可将任务变为 fulfilled 状态, data 为需要传递的相关数据
      resolve('操作成功的结果');
    } else {
      // 调用 reject(reason),可将任务变为 rejected 状态,reason 为需要传递的失败原因
      reject('操作失败的原因');
    }
  }, 1000);
});

p.then((value) => {
  // onFulfilled 函数,当任务完成后,会自动运行该函数,value为任务完成的相关数据
  console.log('异步任务执行成功✌️')
}, (reason) => {
  // onRejected 函数,当任务失败后,会自动运行该函数,reason为任务失败的相关原因
  console.log('异步任务执行失败❌')
})

第二章:使用 Promise

一、Promise 实例对象的两个属性

javascript
const p = new Promise((resolve, reject) => {
    resolve('ok');
})

console.log(p);

执行上面代码,浏览器控制台看到如下内容。

  • PromiseState:此属性为 promise 对象的状态属性。

    • fulfilled:已成功 / 已兑现。
    • rejected:已失败 / 已拒绝。
    • pending:进行中 / 待定。

    【注】状态只能由 pending ➡ fulfilled 或者是 pending ➡ rejected。

  • PromiseResult:此属性为 promise 对象的结果值(resolve 以及 reject 函数的形参值)。

二、Promise 对象的状态

Promise 对象通过自身的状态来控制异步操作,Promise 实例具有三种状态。

  • 异步操作未完成:pending。
  • 异步操作成功:fulfilled。
  • 异步操作失败:rejected。

这三种的状态的变化途径只有两种。

  • 从 pending (未完成) 到 fulfilled (成功) 。
  • 从 pending (未成功) 到 rejected (失败) 。

一旦状态发生变化,就凝固了,不会再有新的状态变化,这也是 Promise 这个名字的由来,它的英语意思"承诺"。意味着 Promise 实例的状态变化只可能发生一次。

在 Promise 对象的构造函数中,将一个函数作为第一个参数。而这个函数,就是用来处理 Promise 的状态变化。

javascript
const p = new Promise((resolve, reject) => {
    resolve('ok');
    // reject('err');
})

console.log(p);

上面的 resolve 和 reject 都为一个函数,他们的作用分别是将状态修改为 fulfilled 和 rejected。

三、Promise 的 then 方法

then:指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调,返回一个新的 promise 对象。

  • 成功的状态:执行第一个回调函数。
  • 失败的状态:执行第二个回调函数。

promise.then() 返回的新 promise 的结果状态由什么决定?

(1) 简单表达:由 then() 指定的回调函数执行的结果决定。

(2) 详细表达

  • 若没有相关的后续处理,新任务的状态和前任务一致,数据为前任务的数据。

  • 若有后续处理但还未执行,新任务挂起。

    会使用这个来终止 Promise 链条。可以在一个 .then() 处理程序中返回一个新的 Promise,这个 Promise 永远不会解析。这将阻止后续的 .then() 处理程序被调用。

    javascript
    new Promise((resolve, reject) => {
        resolve(111);
    }).then(value=>{
        console.log(value);
        console.log(222);
        // return false;
        // throw '出错啦';
        // 有且只有一种方式 返回一个pending状态的promise对象
        return new Promise((resolve, reject) => {});
    }).then(value => {
        console.log(333);
    }).then(value => {
        console.log(444);
    }).catch(reason => {
        console.log(reason);
    });
  • 若后续处理执行了,则根据后续处理的情况确定新任务的状态。

    • 后续处理执行无错,新任务的状态为完成,数据为后续处理的返回值。

      javascript
      const p = new Promise((resolve,reject)=>{
          resolve('ok');
      });
      
      let result = p.then(value=>{
      	return 100;
      },reason=>{
      	console.log(reason);
      });
      
      console.log(result);
    • 后续处理执行有错,新任务的状态为失败,数据为异常对象。

      javascript
      const p = new Promise((resolve,reject)=>{
           resolve('ok');
      });
      
      let result = p.then(value=>{
      	throw '错误';
      },reason=>{
      	console.log(reason);
      });
      
      console.log(result);
    • 后续执行后返回的是一个任务对象,新任务的状态和数据与该任务对象一致。

      javascript
      const p = new Promise((resolve,reject)=>{
          resolve('ok');
      });
      
      let result = p.then(value=>{
      	return new Promise((resolve,reject)=>{
      		// resolve('111');
              reject('error');
      	})
      },reason=>{
      	console.log(reason);
      });
      
      console.log(result);

四、resolve / reject 函数

  • resolve:修改 promise 对象的状态,由 pending 修改到 fulfilled;将实参设置到这个属性 PromiseResult 中。

    • 情况一:如果 resolve 传入一个普通的值或者对象,那么这个值会作为 then 回调的参数。
    • 情况二:如果 resolve 中传入的是另外一个 Promise,那么这个新 Promise 会决定原 Promise 的状态。
    • 情况三:如果 resolve 中传入的是 一个对象,并且这个对象有实现 then 方法,那么会执行该 then 方法 ,并且根据 then 方法的结果来决定 Promise 的状态。
  • reject:修改 promise 对象的状态,由 pending 修改到 rejected;将实参设置到这个属性 PromiseResult 中。

案例 1:利用 promise 进行数据库操作。

javascript
const mongoose = require('mongoose');

new Promise((resolve, reject) => {
    mongoose.connect('mongodb://127.0.0.1/project');
    mongoose.connection.on('open', ()=>{
        //连接成功的情况
        resolve();
    });

    mongoose.connection.on('error', () => {
        //连接失败的情况
        reject();
    })
}).then(value => {
    //创建结构
    const NoteSchema = new mongoose.Schema({
        title: String,
        content: String
    })
    //创建模型
    const NoteModel = mongoose.model('notes', NoteSchema);

    //读取操作
    NoteModel.find().then(value => {
        console.log(value);
    }, reason => {
        console.log(reason);
    })
}, reason => {
    console.log('连接失败');
})

案例 2:封装一个函数,作用是读取文件。

javascript
const fs = require('fs');

function ReadFileFun(path){
    return new Promise((resolve,reject)=>{
         fs.readFile(path,(err,data)=>{
              //判断
              if(err){
                    reject(err)
              }else{
                    resolve(data);
              }
         })
    });
}

ReadFileFun('./data.txt').then(value=>{
    console.log(value.toString());
},reason=>{
    console.log(reason);
})

node 中的 promisify。

  • promisify(只能在 NodeJS 环境中使用)。
  • promisify 是 util 模块中的一个方法,util 是 nodeJS 的内置模块。
  • 作用:返回一个新的函数,此函数用 promise 进行了封装。
javascript
const util = require('util');
const fs = require('fs');
// 通过 fs.readFile 创建一个新的函数
const mineReadFile = util.promisify(fs.readFile);

mineReadFile('./resource/2.html')
.then(value => {
    console.log(value.toString());
}, reason => {
    console.log(reason);
})

五、Promise 的链式调用

基本使用

javascript
const p = new Promise((resolve,reject)=>{
	// resolve('ok');
    reject('error');
});

p.then(value=>{
	console.log(value);
},reason=>{
	console.log(reason);
}).then(value=>{
    console.log("第二次异步任务成功");
	console.log(value);
},reason=>{
    console.log("第二次异步任务失败");
	console.log(reason);
})

这段代码的执行结果将会是:

// 如果为 resolve('ok');
ok
第二次异步任务成功
undefined

// 如果为 reject('error');
error
第二次异步任务成功
undefined

指定多个回调执行情况

问题:一个 promise 指定多个成功 / 失败回调函数,都会调用吗?

答:会,但是前提是当 promise 对象的状态改变(fulfilled / rejected)时才会调用。

javascript
let p = new Promise((resolve, reject) => {
	// promise对象是可以多次调用then方法完成多个成功/失败回调函数
	// 但是使用的前提是这个promise对象的状态必须要么是fulfilled或者是rejected
	// 不能是pending
	resolve('OK');
});

// 第一次指定回调
p.then(value => {
	console.log(value);
}, reason => {
	console.error(reason);
});

p.then(value => {
	alert(value);
}, reason => {
	alert(reason);
})

案例:通过 promise 的链式调用来读取文件

需求:读取 resource 下三个文件内容,并在控制台合并输出。

回调地狱的方式:

javascript
const fs = require('fs');
fs.readFile('./resource/1.html',(err,data1)=>{
    if(err) throw err;
    fs.readFile('./resource/1.html',(err,data2)=>{
    	if(err) throw err;
        fs.readFile('./resource/1.html',(err,data3)=>{
    		if(err) throw err;
            console.log(data1 + data2 + data3);
		})
	})
})

Promise 的形式:

javascript
new Promise((resolve,reject)=>{
	fs.readFile('./resource/1.html',(err,data)=>{
		 // 如果失败 则修改promise对象状态为失败
        if(err) reject(err);
        // 如果成功 则修改promise对象状态为成功
        resolve(data);
	})
}).then(value=>{
    return new Promise((resolve,reject)=>{
        fs.readFile('./resource/2.html',(err,data)=>{
             // 失败
            if(err) reject(err);
            // 成功
            resolve([value,data]);
        })
	})
}).then(value=>{
    return new Promise((resolve,reject)=>{
        fs.readFile('./resource/3.html',(err,data)=>{
             // 失败
            if(err) reject(err);
            value.push(data);
            // 成功
            resolve(value);
        })
	})
}).then(value=>{
    console.log(value.join(""));
})

六、Promise 静态方法

1. Promise.resolve()

将一个普通值转化为 promise 类型的数据。

  • 若参数为非 promise 对象,则返回的结果为成功状态的 promise 对象。
javascript
let p1 = Promise.resolve(123);
console.log(p1);
let p2 = Promise.resolve(undefined);
console.log(p2);
  • 若参数为 promise 对象,参数的状态决定返回结果的状态。
javascript
let p3 = Promise.resolve(new Promise((resolve,reject)=>{
	resolve('success');
}));
console.log(p3);

let p4 = Promise.resolve(Promise.resolve(Promise.resolve("OK")));
console.log(p4);
  • 参数是一个 thenable。
javascript
let thenable = {
  then: function(resolve, reject) {
    resolve('Resolved!');
  }
};

let p = Promise.resolve(thenable);

p.then(value => {
  console.log(value); // 输出 'Resolved!'
});

2. Promise.reject()

Promise.reject 传入的参数无论是什么形态,都会直接作为 reject 状态的参数传递到 catch 的。

javascript
console.log(Promise.reject(123)); // Promise {<rejected>: 123}

console.log(Promise.reject(Promise.resolve('ok'))); // Promise {<rejected>: Promise}

3. Promise.catch()

功能是用来指定失败的回调函数。

then 方法中不是必须传入两个参数,可以只传递成功时的回调函数,也可以单独使用 catch 来指定失败的回调函数。

catch 方法也返回 promise 对象,它的返回结果状态也与 then 一样。

.catch(onRejected) = .then(null, onRejected)。所以 .catch(onRejected).then(null, onRejected) 的语法糖。

javascript
let p = new Promise((resolve,reject)=>{
	// resolve('success');
    reject('error');
});

p.catch(reason=>{
    console.log("第一个catch:" + reason);
});

// 异常(错误)穿透
// 当如果有多个需要执行的成功时的回调函数,可以不需要每一次都写失败回调,可以统一最后利用 catch
// 当如果 promise 对象的状态为 reject 的话,会一直向下穿透直到 catch 方法
p.then(value=>{
    console.log(value);
}).then(value=>{
    console.log(value);
}).catch(reason=>{
    console.log("第二个catch:" + reason);
})

4. Promise.all()

作用:针对于多个 Promise 的异步任务进行处理。

接收的参数:promise 数组。

返回值:promise 对象,状态由 promise 数组中的对象状态决定。

  • 若每个对象状态都为成功,则返回的 promise 对象状态为成功。

​ 成功的结果值为每个 promise 对象结果值组成的数组。

  • 若其中一个对象状态为失败,则返回的 promise 对象状态为失败。

​ 失败的结果值为失败的 promise 对象的结果值。

javascript
let p1 = new Promise((resolve, reject) => {
            resolve('ok');
})
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('oh yeah');
let result = Promise.all([p1, p2, p3]);

result.then(values => {
  console.log(values); // 输出:['ok', 'hello', 'oh yeah']
}).catch(error => {
  console.log(error);
});

注意:

如果在 Promise.all() 的参数中的某个 Promise 实例上定义了 .catch() 方法,那么当这个 Promise 实例被 reject 时,它的错误将会被这个 .catch() 方法捕获,而不会传递给 Promise.all().catch() 方法。

这是因为 .catch() 方法实际上是 .then(null, rejection) 的别名,它会处理 Promise 的错误,并返回一个新的 Promise。当你在一个 Promise 上调用 .catch() 方法并提供一个回调函数时,这个回调函数会在 Promise 被 reject 时执行,并返回一个新的 Promise。这个新的 Promise 默认是 resolved 状态的,除非你在 .catch() 的回调函数中再次抛出错误。

因此,如果在 Promise.all() 的参数中的一个 Promise 上定义了 .catch() 方法,这个 Promise 实例被 reject 时,它的错误将会被这个 .catch() 方法捕获,并返回一个新的 resolved 的 Promise。这就是为什么这个错误不会传递给 Promise.all().catch() 方法的原因。

javascript
let p1 = Promise.reject('失败01').catch(reason => console.log(reason));  // 这里定义了.catch方法
let p2 = Promise.resolve('成功02');
let p3 = Promise.resolve('成功03');

let pAll = Promise.all([p1, p2, p3]);

pAll.then(value => {
  console.log(value);  // 输出: [undefined, '成功02', '成功03']
}).catch(reason => {
  console.log(reason);  // 这里不会被调用,因为p1的错误已经被它自己的.catch方法处理了
});

当有一个 ajax 请求,它的参数需要另外 2 个甚至更多请求都有返回结果之后才能确定,那么这个时候,就需要用到 Promise.all 来帮助我们应对这个场景。

案例1:模拟请求三个接口中的数据,全部请求成功后获取。

javascript
function getUsersList() {
    return new Promise((resolve, reject) => {
        //模拟请求用户列表数据
        setTimeout(() => {
            resolve('用户列表的数据');
        }, 1000);
    })
}
function getBannersList() {
    return new Promise((resolve, reject) => {
        //模拟请求用户列表数据
        setTimeout(() => {
            resolve('轮播图的数据');
        }, 2000);
    })
}
function getVideoList() {
    return new Promise((resolve, reject) => {
        //模拟请求用户列表数据
        setTimeout(() => {
            resolve('视频列表的数据');
        }, 3000);
    })
}
//初始加载的时候
function initLoad() {
    let all = Promise.all([getUsersList(), getBannersList(), getVideoList()]);
    //获取成功请求的结果值
    all.then(value => {
        console.log(value);
    })
}
initLoad();

案例2:修改多文件读取代码。

javascript
const fs = require('fs');
const util = require('util');
const mywriteFile = util.promisify(fs.readFile);
let one = mywriteFile('./resource/1.html');
let two = mywriteFile('./resource/2.html');
let three = mywriteFile('./resource/3.html');
let result = Promise.all([one,two,three]);
result.then(value=>{
    console.log(value.join(''));
},reason=>{
    console.log(reason);
})

5. Promise.allSettled()

all 方法有一个缺陷:当有其中一个 Promise 变成 reject 状态时,新 Promise 就会立即变成对应的 reject 状态。那么对于 resolved 的,以及依然处于 pending 状态的 Promise,是获取不到对应的结果的。

在 ES11(ES2020)中,添加了新的 API:Promise.allSettled。

Promise.allSettled(iterable) 方法返回一个在所有给定的 Promise 都已经完成(无论是 fulfilled 还是 rejected)后的 Promise。并且这个 Promise 的结果一定是 fulfilled 的。返回值是一个对象数组,每个对象表示对应的 Promise 结果。结果数组中的每个对象都有两个属性:

  • status:字符串,表示 Promise 是 fulfilled 还是 rejected。
  • value:这个 Promise 的返回值(如果状态是 fulfilled)。
  • reason:这个 Promise 的拒绝原因(如果状态是 rejected)。
javascript
let p1 = Promise.resolve(3);
let p2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
let promises = [p1, p2];

console.log(Promise.allSettled(promises))

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// 输出:
// "fulfilled"
// "rejected"

6. Promise.race()

race 赛跑的意思。

参数:promise 数组

返回结果:promise 对象

​ 结果值、状态都由『最先改变状态的 promise 对象』决定。

javascript
let p1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve('ok');
    }, 2000)
});

let p2 = Promise.resolve('success');
let p3 = Promise.resolve('oh hou');

Promise.race([p1, p2, p3]).then(result => {
    console.log(result); // success
})

与 Promise.all 相似的是,Promise.race 都是以一个 Promise 对象组成的数组作为参数。

不同的是,只要当数组中的其中一个 Promsie 状态变成 resolved 或者 rejected 时,就可以调用 then 方法了。而传递给 then 方法的值也会有所不同。

javascript
// 这是我们的主要任务,我们假设它需要2秒才能完成
let mainTask = new Promise((resolve, reject) => {
  setTimeout(resolve, 2000, 'Main task completed');
});

// 这是我们的超时任务,我们设置它在1秒后自动reject
let timeoutTask = new Promise((resolve, reject) => {
  setTimeout(reject, 1000, 'Timeout');
});

// 我们将这两个任务一起传递给Promise.race()
Promise.race([mainTask, timeoutTask])
  .then(value => {
    // 如果mainTask在timeoutTask之前完成,这个回调将会被调用
    console.log(value);
  })
  .catch(reason => {
    // 如果timeoutTask在mainTask之前完成(即发生超时),这个回调将会被调用
    console.log(reason);
  });

7. Promise.any()

ES12 中新增的方法。

只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfiilled 状态。

如果所有参数实例都变成 rejected,包装实例就会变成 rejected 状态。那么会报一个 AggregateError 的错误。

javascript
let p1 = new Promise((resolve, reject) => setTimeout(reject, 100, 'p1 rejected'));
let p2 = new Promise((resolve, reject) => setTimeout(resolve, 200, 'p2 resolved'));
let p3 = new Promise((resolve, reject) => setTimeout(reject, 300, 'p3 rejected'));

Promise.any([p1, p2, p3])
  .then(value => console.log(value))
  .catch(error => console.log(error));

// 输出:
// "p2 resolved"

8. Promise.finally()

finally 是在 ES9 (ES2018) 中新增的一个特性:表示无论 Promise 对象变成 fufilled 还是 rejected 状态,最终都会被执行。

finally 方法中的回调函数是不接受参数的,因为无论前面是 fulfilled 状态还是 rejected 状态,它都是执行。

javascript
const p = new Promise((resolve, reject) => {
    // resolve('ok');
    reject('error');
});
p.then(res => {
    console.log(res);
}).catch(err => {
    console.log(err);
}).finally(() => {
    console.log('finally')
})

七、async 和 await

async / await 是 ES7 提出的基于 Promise 的解决异步的最终方案。

一、原理

需求:封装一个网络请求的方法。

javascript
function requestData(url) {
  return new Promise((resolve, reject) => {
	setTimeout(() => {
      // 发起网络请求的伪代码 ...
      // let response = request(url)
      // 返回请求结果
	  resolve(response)
	}, 2000)
  })
}

// 发送一次网络请求
requestData("http://why").then(res => {
  console.log("res:", res)
})

需求:发送第一次网络请求,等到这次网络请求的结果之后,在发送第二次网络请求,等待这次网络请求的结果之后,在发送第三次网络请求,等待这次网络请求的结果。

javascript
// 方式一: 层层嵌套(回调地狱 callback hell)
function getData() {
  // 1.第一次请求
  requestData("why").then(res1 => {
	console.log("第一次结果:", res1)

	// 2.第二次请求
	requestData(res1 + "kobe").then(res2 => {
	  console.log("第二次结果:", res2)

	  // 3.第三次请求
	  requestData(res2 + "james").then(res3 => {
		console.log("第三次结果:", res3)
	  })
	})
  })
}

// 方式二: 使用 Promise 进行重构(解决回调地狱)
// 链式调用
function getData() {
  requestData("why").then(res1 => {
	console.log("第一次结果:", res1)
	return requestData(res1 + "kobe")
  }).then(res2 => {
	console.log("第二次结果:", res2)
	return requestData(res2 + "james")
  }).then(res3 => {
	console.log("第三次结果:", res3)
  })
}

// 方式三: 最终代码
function* getData() {
  const res1 = yield requestData("why")
  console.log("res1:", res1)

  const res2 = yield requestData(res1 + "kobe")
  console.log("res2:", res2)

  const res3 = yield requestData(res2 + "james")
  console.log("res3:", res3)
}

const generator = getData()
generator.next().value.then(res1 => {
  generator.next(res1).value.then(res2 => {
	generator.next(res2).value.then(res3 => {
	  generator.next(res3)
	})
  })
})

// 方式四: async/await 的解决方案
async function getData() {
  const res1 = await requestData("why")
  console.log("res1:", res1)

  const res2 = await requestData(res1 + "kobe")
  console.log("res2:", res2)

  const res3 = await requestData(res2 + "james")
  console.log("res3:", res3)
}

const generator = getData()

方法三的优化。

javascript
// 自动化执行生成器函数(了解)
function execGenFn(genFn) {
  // 1.获取对应函数的generator
  const generator = genFn()
  // 2.定义一个递归函数
  function exec(res) {
	// result -> { done: true/false, value: 值/undefined }
	const result = generator.next(res)
	if (result.done) return
	result.value.then(res => {
	  exec(res)
	})
  }
  // 3.执行递归函数
  exec()
}

execGenFn(getData)

二、async 函数

async 是一个加在函数前的修饰符,被 async 定义的函数会默认返回一个 Promise 对象 resolve 的值。

因此对 async 函数可以直接 then,返回值就是 then 方法传入的函数。

返回值

情况一:异步函数也可以有返回值,但是异步函数的返回值相当于被包裹到 Promise.resolve 中。

情况二:如果我们的异步函数的返回值是 Promise,状态由会由 Promise 决定。

情况三:如果我们的异步函数的返回值是一个对象并且实现了 thenable,那么会由对象的 then 方法来决定。

异常处理

如果在 async 中抛出了异常,那么程序它并不会像普通函数一样报错,而是会作为 Promise 的 reject 来传递。

javascript
// async基础语法
async function fun0(){
    console.log(1);
    return 1;
}
fun0().then(val=>{
    console.log(val) // 1,1
})

async function fun1(){
    console.log('Promise');
    return new Promise(function(resolve,reject){
        resolve('Promise')
    })
}
fun1().then(val => {
    console.log(val); // Promise Promise
}
javascript
//声明一个async函数
async function main() {
    console.log('async function');
    //情况1:返回非promise对象数据
    return 'hahaha';
    //情况2:返回是promise对象数据
    /* return new Promise((resolve, reject) => {
		// resolve('ok');
		reject('error');
	}) */
    //情况3:抛出异常
    // throw new Error('出错啦!!!');
}
let result = main().then(value => {
    console.log(value);
});
console.log(result);

三、await 表达式

await 也是一个修饰符,只能放在 async 定义的函数内。可以理解为等待。

await 修饰的如果是 Promise 对象,可以获取 Promise 中返回的内容(resolve 或 reject 的参数),且取到值后语句才会往下执行;如果不是 Promise 对象:把这个非 promise 的东西当做 await 表达式的结果。

返回值

如果 await 后面是一个 普通的值,那么会直接返回这个值。

如果 await 后面是一个 thenable 的对象,那么会根据对象的 then 方法调用来决定后续的值。

如果 await 后面的表达式,返回的 Promise 是 reject 的状态 ,那么会将这个 reject 结果直接作为函数的 Promise 的 reject 值。

注意事项

  • await 必须写在 async 函数中,但是 async 函数中可以没有 await。
  • 如果 await 的 promise 失败了,就会抛出异常,需要通过 try...catch 捕获处理。
javascript
async function fun(){
    let a = await 1;
    let b = await new Promise((resolve,reject)=>{
        setTimeout(function(){
            resolve('setTimeout')
        },3000)
    })
    let c = await function(){
        return 'function'
    }()
    console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"
javascript
function log(time){
    setTimeout(function(){
        console.log(time);
        return 1;
    },time)
}
async function fun(){
    let a = await log(1000);
    let b = await log(3000);
    let c = log(2000);
    console.log(a);
    console.log(1)
}
fun(); 
// 立即输出 undefined 1
// 1秒后输出 1000
// 2秒后输出 2000
// 3秒后输出 3000
javascript
async function main() {
    //1、如果await右侧为非promise类型数据
    var rs = await 10;
    var rs = await 1 + 1;
    var rs = await "非常6+7";

    //2、如果await右侧为promise成功类型数据
    var rs = await new Promise((resolve, reject) => {
        resolve('success');
    })

    //3、如果await右侧为promise失败类型数据,需要借助于try...catch捕获
    try {
        var rs = await new Promise((resolve, reject) => {
            reject('error');
        })
        } catch (e) {
            console.log(e);
        }
}
main();
javascript
// 使用async/await获取成功的结果

// 定义一个异步函数,3秒后才能获取到值(类似操作数据库)
function getSomeThing(){
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            resolve('获取成功')
        },3000)
    })
}

async function test(){
    let a = await getSomeThing();
    console.log(a)
}
test(); // 3秒后输出:获取成功

案例:async结合await读取文件内容

javascript
//1、导包
const fs = require('fs');
const {promisify} = require('util');
//2、将fs.readFile转化成promise风格的函数
const myreadfile = promisify(fs.readFile);
//3、声明async函数
async function main(){
    try{
        //4、读取文件
        let one = await myreadfile('./resource/4.html');
        let two = await myreadfile('./resource/2.html');
        let three = await myreadfile('./resource/3.html');
    //5、拼接读取文件内容
    console.log(one + two + three);
    }catch(e){
        console.log(e);
    }
}
//6、调用main函数
main();

随堂练习

1. 指定回调与改变状态先后顺序问题

改变 promise 状态和指定回调函数执行谁先谁后?

  • 都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态在指定回调

    javascript
    //若执行器函数中是异步任务, 则先指定回调, 然后再改变状态  更为常见
    //若执行器函数中是同步任务, 则先改变状态, 然后再指定回调
    let p = new Promise((resolve, reject) => {
        //同步任务
        //resolve('ok');
        //异步任务
        setTimeout(() => {
            resolve('ok');
        }, 1000);
    });
  • 如何先改状态再指定回调?

    • 在执行器中直接调用resolve()/reject()
    javascript
    let p = new Promise((resolve, reject) => {
    	//resolve('ok');
    	reject('error');
    });
    • 延迟更长时间才调用then()
    javascript
    const p = new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('ok');
        }, 1000)
    
    })
    //then方法使用定时器延迟更久的时间
    setTimeout(() => {
        p.then(value => {
            console.log(value);
        }, reason => {
            console.log(reason);
        })
    
    }, 3000)
  • 什么时候才能得到数据?

    • 如果是先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据
    • 如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

另一种解释。

执行器函数(executor function)是在创建新的 Promise 对象时传入的函数。这个函数接受两个参数:resolvereject,它们是两个函数,用于改变 Promise 的状态。

当执行器函数中的任务是异步的(例如,一个网络请求或者一个定时器),通常的模式是先指定回调函数(通过 .then().catch()),然后在异步任务完成时调用 resolvereject 来改变 Promise 的状态。这样,当异步任务完成时,相应的回调函数就会被调用。例如:

javascript
let p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('Hello, world!');
  }, 1000);
});

p.then(value => {
  console.log(value); // 1秒后输出 "Hello, world!"
});

在这个例子中,我们首先指定了一个回调函数,然后在 setTimeout 完成时调用 resolve

当执行器函数中的任务是同步的(例如,一个计算任务),通常的模式是先改变 Promise 的状态(通过调用 resolvereject),然后指定回调函数。这样,回调函数会在当前的 JavaScript 事件循环结束时被调用。例如:

javascript
let p = new Promise((resolve, reject) => {
  resolve('Hello, world!');
});

p.then(value => {
  console.log(value); // 立即输出 "Hello, world!"
});

在这个例子中,我们首先调用 resolve 改变 Promise 的状态,然后指定了一个回调函数。这个回调函数会在当前的 JavaScript 事件循环结束时被调用。

执行器函数中的任务(也就是异步操作)可能是同步的,也可能是异步的。如果是同步的,那么状态的改变可能会在回调函数被指定之前就发生;如果是异步的,那么回调函数的指定可能会在状态的改变之前就发生。但是无论哪种情况,只要 Promise 的状态改变,相应的回调函数就会被调用。

第三章:浏览器的事件循环

一、为什么要有事件循环

浏览器有哪些进程和线程?

浏览器是一个多进程多线程的应用程序。

浏览器内部工作极其复杂。为了避免相互影响,为了减少连环崩溃的几率,当启动浏览器后,它会自动启动多个进程。

最主要的进程有:

  1. 浏览器进程

    主要负责界面显示、用户交互、子进程管理等。浏览器进程内部会启动多个线程处理不同的任务。

  2. 网络进程

    负责加载网络资源。网络进程内部会启动多个线程来处理不同的网络任务。

  3. 渲染进程(重点)

    渲染进程启动后,会开启一个渲染主线程,主线程负责执行 HTML、CSS、JS 代码。

    默认情况下,浏览器会为每个标签页开启一个新的渲染进程,以保证不同的标签页之间不相互影响。

渲染主线程是如何工作的?

渲染主线程是浏览器中最繁忙的线程,需要它处理的任务包括但不限于:

  • 解析 HTML
  • 解析 CSS
  • 计算样式
  • 布局
  • 处理图层
  • 每秒把页面画 60 次
  • 执行全局 JS 代码
  • 执行事件处理函数
  • 执行计时器的回调函数
  • ......

要处理这么多的任务,主线程遇到了一个前所未有的难题:如何调度任务?

比如:

  • 我正在执行一个 JS 函数,执行到一半的时候用户点击了按钮,我该立即去执行点击事件的处理函数吗?
  • 我正在执行一个 JS 函数,执行到一半的时候某个计时器到达了时间,我该立即去执行它的回调吗?
  • 浏览器进程通知我“用户点击了按钮”,与此同时,某个计时器也到达了时间,我应该处理哪一个呢?
  • ......

渲染主线程想出了一个绝妙的主意来处理这个问题:排队。

  1. 在最开始的时候,渲染主线程会进入一个无限循环。
  2. 每一次循环会检查消息队列中是否有任务存在。如果有,就取出第一个任务执行,执行完一个后进入下一次循环;如果没有,则进入休眠状态。
  3. 其他所有线程(包括其他进程的线程)可以随时向消息队列添加任务。新任务会加到消息队列的末尾。在添加新任务时,如果主线程是休眠状态,则会将其唤醒以继续循环拿取任务。

这样一来,就可以让每个任务有条不紊的、持续的进行下去了。

整个过程,被称之为事件循环(消息循环)。

何为异步?

代码在执行过程中,会遇到一些无法立即处理的任务,比如:

  • 计时完成后需要执行的任务 —— setTimeoutsetInterval
  • 网络通信完成后需要执行的任务 -- XHRFetch
  • 用户操作后需要执行的任务 -- addEventListener

如果让渲染主线程等待这些任务的时机达到,就会导致主线程长期处于「阻塞」的状态,从而导致浏览器「卡死」。

渲染主线程承担着极其重要的工作,无论如何都不能阻塞!

因此,浏览器选择异步来解决这个问题。

使用异步的方式,渲染主线程永不阻塞。

二、消息队列

1. 新说法

任务没有优先级,在消息队列中先进先出。但消息队列是有优先级的

随着浏览器的复杂度急剧提升,W3C 不再使用宏队列的说法。W3C 的最新解释:

  • 每个任务都有一个任务类型,同一个类型的任务必须在一个队列,不同类型的任务可以分属于相同的队列。 在一次事件循环中,浏览器可以根据实际情况从不同的队列中取出任务执行。
  • 浏览器必须准备好一个微队列,微队列中的任务优先所有其他任务执行。

在目前 chrome 的实现中,至少包含了下面的队列:

  • 延时队列:用于存放计时器到达后的回调任务,优先级「中」
  • 交互队列:用于存放用户操作后产生的事件处理任务,优先级「高」
  • 微队列:用户存放需要最快执行的任务,优先级「最高」

优先级:微队列 > 交互队列 > 延时队列

2. 旧说法

宏任务队列(macrotask queue):ajax、setTimeout、setInterval、DOM 监听 (事件处理函数) 、UI Rendering、requestAnimationFrame 的回调等。

微任务队列(microtask queue):Promise 的 then 回调、Mutation Observer API、queueMicrotask 等。

那么事件循环对于两个队列的优先级是怎么样的呢?

1)main script 中的代码优先执行(编写的顶层 script 代码)。

2)在执行任何一个宏任务之前(不是队列,是一个宏任务),都会先查看微任务队列中是否有任务需要执行。也就是宏任务执行之前,必须保证微任务队列是空的;如果不为空,那么就优先执行微任务队列中的任务(回调)。

同 > 微 > 宏

第四章:手写 promise

十五、手写promise自定义基础结构的搭建

15.1 Promise 的基本结构

js
/**
 * 1- Promise 是一个构造函数
 * 2- Promise 接收一个参数,该参数的类型是函数(执行器函数executor)
 * 3- executor接收两个参数(resolve,reject),参数的类型是函数
 * 4- 执行器函数会同步执行。
 * 5- then方法在其显式原型属性上
 */

// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
    // executor是执行器函数
    function Promise(executor){
        executor(function(){

        },function(){

        });
    }
    window.Promise = Promise;
})(window);
js
new Promise((resolve, reject)=>{
    console.log("这是我的执行器函数",resolve,reject)
})
console.log("over",Promise);

15.2 Promise实例拥有两个实例属性

js
/*
 * 1- Promise实例拥有两个实例属性:
 * 状态([[PromiseState]]),初始状态为pending
 * 值([[PromiseResult]]),初始值为undefined
*/
js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		executor(function(){
		
		},function(){
		
		});
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
	console.log("这是我的执行器函数",resolve,reject)
})
console.log(p1);

15.3 更改状态三种方式-方法未抽离

js
/*
 * 更改状态三种方式
 * 1- 通过调用resolve将状态更改为成功(fulfilled),接收的值为成功值
 * 2- 通过调用reject将状态更改为失败(rejected),接收的值为失败值
 * 3- 抛出异常将状态更改为失败(rejected),失败的值为异常信息。
*/
js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		try{
			executor(function(value){
				// 将状态更改为成功(fulfilled)
				this.state = "fulfilled";
				// 成功值为value
				this.result = value;
			}.bind(this),function(value){
				// 将状态更改为失败
				this.state = "rejected";
				// 将result设置为value
				this.result = value;
			}.bind(this));
		}catch (err){
			// 将状态更改为失败
			this.state = "rejected";
			// 将异常信息作为失败值
			this.result = err;
		}
		
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    // reject(2);
    throw "异常"
})
console.log(p1);

15.4 更改状态三种方式-抽离为普通函数

js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = function(value){
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}.bind(this)
		// 定义reject函数
		const _reject = function(value){
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}.bind(this)
		try{
			executor(_resolve,_reject);
		}catch (err){
			// 将状态更改为失败
			this.state = "rejected";
			// 将异常信息作为失败值
			this.result = err;
		}
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    reject(2);
    // throw "异常"
})
console.log(p1);

15.5 更改状态三种方式-抽离为箭头函数

js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			// 将状态更改为失败
			this.state = "rejected";
			// 将异常信息作为失败值
			this.result = err;
		}
		
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    // reject(2);
    throw "异常"
})
console.log(p1);

15.6 状态只允许更改一次

js
/*
 * pending-> fulfilled
 * pending-> rejected
 * 改变状态只有这两种,且一个promise对象只能改变一次,,无论变成成功还是失败,都会有一个结果值
 * 成功的结果数据一般称为value,失败的结果值一般称为reason
*/
js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    resolve(1);
    reject(2);
    throw "异常"
})
console.log(p1);

15.7 then函数调用成功或失败回调函数

js
/*
 * 1- then是Promise中的原型方法
 * 2- then函数接收两个参数(成功回调,失败回调)
 * 3- 如果p1状态为成功执行成功回调,失败执行失败回调。
*/
js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 状态成功调用onResolved
			if(this.state === "fulfilled"){
				onResolved(this.result);
			}else if(this.state === "rejected"){
				onRejected(this.result);
			}
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);

15.8 then函数中的回调函数是异步调用的

js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 状态成功调用onResolved
			if(this.state === "fulfilled"){
				// 异步调用
				setTimeout(()=>{
					onResolved(this.result);
				})
				
			}else if(this.state === "rejected"){
				// 异步调用
				setTimeout(()=>{
					onRejected(this.result);
				})
			}
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    // reject(2);
    throw "异常"
})
p1.then(value=>{
    console.log("成功回调",value);
},reason=>{
    console.log("失败回调",reason);
})
console.log("over");

15.9 then函数返回的是一个Promise实例

js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			return new Promise((resolve,reject)=>{
				// 状态成功调用onResolved
				if(this.state === "fulfilled"){
					// 异步调用
					setTimeout(()=>{
						onResolved(this.result);
					})
					
				}else if(this.state === "rejected"){
					// 异步调用
					setTimeout(()=>{
						onRejected(this.result);
					})
				}
			})
			
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    // reject(2);
    throw "异常"
})
const p2 = p1.then(value=>{
    console.log("成功回调",value);
},reason=>{
    console.log("失败回调",reason);
})
console.log(p2);

15.10 then函数返回的Promise实例状态以及值-未优化

js
/*
 * then返回的Promise实例受成功或失败回调函数返回值的影响
 * 1- 如果返回的是非Promise,那么p2状态为成功,值为返回值
 * 2- 如果返回的是Promise,那么p2状态以及值与返回的状态,值相同。
 * 3- 如果出现异常,那么p2状态为失败,值为异常信息。
*/
js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			return new Promise((resolve,reject)=>{
				// 状态成功调用onResolved
				if(this.state === "fulfilled"){
					// 异步调用
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = onResolved(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise){
								// value.then(v=>{
								// 	// 将返回的Promise实例设置为成功,值为v
								// 	resolve(v);
								// },s=>{
								// 	// 将返回的Promise实例设置为失败,值为s
								// 	reject(s);
								// })
								
								// 简化:
								value.then(resolve,reject)
							}else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
					
				}else if(this.state === "rejected"){
					// 异步调用
					setTimeout(()=>{
						try{
							// value是失败回调的返回值
							const value = onRejected(this.result);
							// value是否为Promise实例
							if(value instanceof Promise){
								// 将返回Promise设置为与value相同的结果
								value.then(resolve,reject);
							}else{
								// 返回成功promise,值为value
								resolve(value);
							}
						}catch (err){
							// 返回失败promise,值为err
							reject(err);
						}
						
					})
				}
			})
			
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    reject(2);
    // throw "异常"
})
const p2 = p1.then(value=>{
    return new Promise((resolve,reject)=>{
        // resolve(100)
        // reject(200)
        throw "异常2"
    })
    // return 1;
    // console.log("成功回调",value);
},reason=>{
    return new Promise((resolve,reject)=>{
        // resolve(100);
        // reject(2)
        throw "异常3"
    })
    // return 1;
    // console.log("失败回调",reason);
})
console.log(p2);

15.11 then函数返回的Promise实例状态以及值-优化封装函数_common

js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise){
								value.then(resolve,reject);
							}else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}
			})
			
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve, reject)=>{
    // resolve(1);
    reject(2);
    // throw "异常"
})
const p2 = p1.then(value=>{
    // return new Promise((resolve,reject)=>{
    // 	// resolve(100)
    // 	// reject(200)
    throw "异常2"
    // })
    // return 1;
    // console.log("成功回调",value);
},reason=>{
    // return new Promise((resolve,reject)=>{
    // 	// resolve(100);
    // 	// reject(2)
    // 	throw "异常3"
    // })
    // return 1;
    // console.log("失败回调",reason);
})
console.log(p2);

15.12 增加成功与失败回调函数的默认值

js
/*
 * 1- then如果省略成功回调,默认成功回调为 value=>value;
 * 2- then如果省略失败回调,默认失败回调为 reason=>{throw reason};
*/
js
// 立即调用函数的好处:可以避免对外部的变量造成污染。
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
		
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise){
								value.then(resolve,reject);
							}else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}
			})
			
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve,reject)=>{
    resolve(1);
    // reject(2);
})
const p2 = p1.then();
console.log(p2);

15.14 执行器函数常用于处理异步行为

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = {};
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			if(this.callbackFn.onResolved){
				this.callbackFn.onResolved();
			}
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "fulfilled";
			// 将result设置为value
			this.result = value;
			if(this.callbackFn.onRejected){
				this.callbackFn.onRejected();
			}
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn = {
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					}
				}
			})
			
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject(100);
    })
})
p1.then(value=>{
    console.log(value);
},reason=>{
    console.log("失败",reason);
})

15.15 可以指定多个成功或失败的回调

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "fulfilled";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(){
		
		}
	})
	window.Promise = Promise;
})(window);
js
// 可以指定多个成功或失败的回调
const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject(100);
    })
})
p1.then(value=>{
    console.log("成功1",value);
},reason=>{
    console.log("失败1",reason);
})
p1.then(value=>{
    console.log("成功2",value);
},reason=>{
    console.log("失败2",reason);
})
p1.then(value=>{
    console.log("成功3",value);
},reason=>{
    console.log("失败3",reason);
})
p1.then(value=>{
    console.log("成功4",value);
},reason=>{
    console.log("失败4",reason);
})

15.16 catch

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "fulfilled";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(onRejected){
			return this.then(undefined,onRejected)
		}
	})
	window.Promise = Promise;
})(window);
js
// 可以指定多个成功或失败的回调
const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject(100);
    })
})
// p1.then(undefined,reason=>{
// 	console.log(reason);
// })
// catch的返回值是Promise实例,实例的属性与值取决于回调函数的返回值
// 返回值为非Promise实例,那么得到的状态为成功,值为返回值
// 返回值为Promise实例,那么得到的结果与返回的结果相同。
// 有异常,那么得到的状态为失败,值为异常信息。
const p2 = p1.catch(reason=>{
    // console.log(reason);
    return new Promise((resolve,reject)=>{
        resolve(2);
    })
    // throw "异常"
})
console.log(p2);

15.17 链式调用支持

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(onRejected){
			return this.then(undefined,onRejected)
		}
	})
	window.Promise = Promise;
})(window);
js
new Promise((resolve,reject)=>{
    resolve(1);
}).then(value=>{
    console.log(value);// 1
    return 2;
}).then(value=>{
    console.log(value);// 2
    return 3;
}).then(value=>{
    console.log(value);// 3
    return 4;
}).then(value=>{
    console.log(value);// 4
    return 5;
})

15.18 异常穿透支持

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(onRejected){
			return this.then(undefined,onRejected)
		}
	})
	window.Promise = Promise;
})(window);
js
new Promise((resolve, reject) => {
    resolve(1);
}).then(value => {
    throw "异常"
}).then(value => {
    console.log(value);
    return 3;
}).then(value => {
    console.log(value);// 3
    return 4;
}).then(value => {
    console.log(value);// 4
    return 5;
}).catch(reason => {
    console.log(4,reason);
})

15.19 中断Promise链

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(onRejected){
			return this.then(undefined,onRejected)
		}
	})
	window.Promise = Promise;
})(window);
js
new Promise((resolve,reject)=>{
    resolve(1);
}).then(value=>{
    console.log(value);// 1
    return 2;
}).then(value=>{
    console.log(value);// 2
    // 在回调函数中返回一个`pendding`状态的promise对象
    return new Promise(()=>{})
}).then(value=>{
    console.log(value);// undefined
    return 4;
}).then(value=>{
    console.log(value);// 4
    return 5;
})

15.20 resolve

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(onRejected){
			return this.then(undefined,onRejected)
		}
	})
	Promise.resolve = function(value){
		if(value instanceof Promise){
			return value;// 如果是Promise实例直接返回
		}else{
			// 如果不是Promise实例,那么返回的状态为成功,值为value
			return new Promise(resolve=>{
				resolve(value);
			})
		}
	}
	window.Promise = Promise;
})(window);
js
// const p1 = Promise.resolve(1);
// console.log(p1);

// const p1 = Promise.resolve(new Promise((resolve,reject)=>{
// 	resolve(2);
// }));
// console.log(p1);
//
// const p1 = Promise.resolve(new Promise((resolve,reject)=>{
// 	reject(2);
// }));
// console.log(p1);


const p =new Promise((resolve,reject)=>{
    reject(2);
})
const p1 = Promise.resolve(p);
console.log(p1===p);

15.21 reject

js
(function(window){
	// executor是执行器函数
	function Promise(executor){
		// 记录成功与失败回调函数
		this.callbackFn = [];
		// 定义实例属性state,初始值为pending
		this.state = "pending";
		// 定义实例属性result,初始值为undefined
		this.result = undefined;
		// 定义resolve函数
		const _resolve = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为成功(fulfilled)
			this.state = "fulfilled";
			// 成功值为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onResolved()
			})
		}
		// 定义reject函数
		const _reject = value=>{
			// 当状态已经被更改过,不允许再次更改
			if(this.state !== "pending") return;
			// 将状态更改为失败
			this.state = "rejected";
			// 将result设置为value
			this.result = value;
			this.callbackFn.forEach(item=>{
				item.onRejected()
			})
		}
		try{
			executor(_resolve,_reject);
		}catch (err){
			_reject(err);// 状态更改为失败,值为异常信息
		}
	}

	Object.assign(Promise.prototype,{
		// onResolved:成功回调
		// onRejected:失败回调
		then(onResolved,onRejected){
			// 如果成功回调不是函数,那么增加成功回调默认值
			if(!(onResolved instanceof Function)){
				onResolved = value=>value;
			}
			// 如果失败回调不是函数,那么增加失败回调默认值
			if(!(onRejected instanceof Function)){
				onRejected = reason=>{
					throw reason;
				};
			}
			return new Promise((resolve,reject)=>{
				const _common = function(callback){
					setTimeout(()=>{
						try{
							// value是成功回调的返回值
							const value = callback(this.result);
							// 判断value是不是通过Promise实例化出来的(判断value是否为Promise实例)
							if(value instanceof Promise) value.then(resolve,reject);
							else{
								// 不是Promise实例,将返回的Promise状态设置为成功,值为value
								resolve(value);
							}
						}catch (err){
							// 有异常,将返回Promise的状态更改为失败,值为err
							reject(err);
						}
						
					})
				}
				// 状态成功调用onResolved
				// p1的状态为成功
				if(this.state === "fulfilled"){
					_common.call(this,onResolved);
				}else if(this.state === "rejected"){
					_common.call(this,onRejected);
				}else{
					// pending
					// 如果状态为pending,那么保存成功与失败回调
					this.callbackFn.push({
						onResolved:_common.bind(this,onResolved),
						onRejected:_common.bind(this,onRejected)
					})
				}
			})
			
		},
		catch(onRejected){
			return this.then(undefined,onRejected)
		}
	})
	Promise.resolve = function(value){
		if(value instanceof Promise){
			return value;// 如果是Promise实例直接返回
		}else{
			// 如果不是Promise实例,那么返回的状态为成功,值为value
			return new Promise(resolve=>{
				resolve(value);
			})
		}
	}
	Promise.reject = function(value){
		return new Promise((resolve,reject)=>{
			reject(value);
		})
	}
	window.Promise = Promise;
})(window);
js
const p1 = Promise.reject(1);
console.log(p1);

const p2 = Promise.reject(new Promise((resolve,reject)=>{
    resolve(2);
}));
console.log(p2);

const p3 = Promise.reject(new Promise((resolve,reject)=>{
    reject(2);
}));
console.log(p3);

15.22 完成all

js
(function (window) {
	// 接收执行器函数(executor),执行器函数会同步执行(立即执行)。
	function Promise(executor) {
		this.state = "pending";// 初始状态
		this.result = undefined;// 初始值
		this.callbackFn = [];
		// _resolve函数将状态更新为成功,成功值为接收的value
		const _resolve = value => {
			// 如果状态已经更改,直接跳出函数体
			if (this.state !== "pending") return;
			this.state = "fulfilled";// 状态更新为成功
			this.result = value;// 更新成功值
			this.callbackFn.forEach(item=>{
				item.onResolved();
			})
		}
		// _reject函数将状态更新为失败,失败值为接收的value
		const _reject = value => {
			// 如果状态已经更改,直接跳出函数体
			if (this.state !== "pending") return;
			this.state = "rejected";// 状态更新为失败
			this.result = value;// 更新失败值
			this.callbackFn.forEach(item=>{
				item.onRejected();
			})
		}
		try {
			executor(_resolve, _reject);
		} catch (err) {
			// 如果有异常,将状态更新为失败,失败的值为异常信息
			_reject(err);
		}
	}
	
	// 将第二个参数(对象)合并至Promise.prototype对象中。
	Object.assign(Promise.prototype, {
		// 1- 接收成功与失败回调函数
		// 2- 返回的是一个Promise实例
		// 3- onResolved成功回调,默认值为value=>value;
		// 4- onRejected失败回调,默认值为reason=>{throw reason};
		then(onResolved, onRejected) {
			// onResolved成功回调,默认值为value=>value;
			if (!(onResolved instanceof Function)) onResolved = value => value;
			//onRejected失败回调,默认值为reason=>{throw reason};
			if (!(onRejected instanceof Function)) onRejected = reason => {
				throw reason
			};
			return new Promise((resolve, reject) => {
				// callback是成功或失败回调
				const _common = function (callback) {
					setTimeout(()=>{
						try {
							// value是成功回调返回结果
							const value = callback(this.result);
							// 判断是否为Promise实例
							if (value instanceof Promise) {
								value.then(resolve, reject);
							} else {
								// 非Promise实例
								resolve(value);
							}
						} catch (err) {
							reject(err);
						}
					})
					
				}
				// 判断状态为成功,调用成功回调
				if (this.state === "fulfilled") _common.call(this, onResolved);
				else if (this.state === "rejected") _common.call(this, onRejected);
				else {
					this.callbackFn.push({
						onResolved: _common.bind(this, onResolved),
						onRejected: _common.bind(this, onRejected)
					})
				}
			})
		},
		catch(onRejected){
			return this.then(undefined,onRejected);
		}
	})
	Promise.resolve = function(value){
		// 判断接收的参数是否为Promise实例,如果是直接返回
		if(value instanceof Promise){
			return value;
		}else{
			// 如果不是,创建一个新的Promise,状态为成功,值为value;
			return new Promise(resolve=>{
				resolve(value);
			})
		}
	}
	Promise.reject = function(value){
		// 返回失败的Promise,失败值为接收的value
		return new Promise((resolve,reject)=>{
			reject(value);
		})
	}
	// 1- 接收的是数组,返回的是Promise
	Promise.all = function(promiseArr){
		let index = 0;
		let successArr = new Array(promiseArr.length);
		return new Promise((resolve,reject)=>{
			promiseArr.forEach((value,i)=>{
				value.then(v=>{
					index++;
					successArr[i] = v;
					if(index === promiseArr.length){
						resolve(successArr);
					}
				},s=>{
					// 返回Promise的状态设置失败
					reject(s);
				})
			})
		})
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(100)
    },100)
})
const p2 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(200)
    },50)
})
const p3 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(300)
    },200)
})
const p4 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(400)
    },100)
})
// all接收的数组中的元素是Promise实例。
// 元素中的Promise实例都成功,p的状态为成功,值为数组,数组的元素为成功值
// 元素中有一个失败,那么p的状态为失败,值为失败值
const p = Promise.all([p1,p2,p3,p4]);
console.log(p);

15.23 完成race

js
(function (window) {
    // 接收执行器函数(executor),执行器函数会同步执行(立即执行)。
    function Promise(executor) {
        this.state = "pending";// 初始状态
        this.result = undefined;// 初始值
        this.callbackFn = [];
        // _resolve函数将状态更新为成功,成功值为接收的value
        const _resolve = value => {
            // 如果状态已经更改,直接跳出函数体
            if (this.state !== "pending") return;
            this.state = "fulfilled";// 状态更新为成功
            this.result = value;// 更新成功值
            this.callbackFn.forEach(item=>{
                item.onResolved();
            })
        }
        // _reject函数将状态更新为失败,失败值为接收的value
        const _reject = value => {
            // 如果状态已经更改,直接跳出函数体
            if (this.state !== "pending") return;
            this.state = "rejected";// 状态更新为失败
            this.result = value;// 更新失败值
            this.callbackFn.forEach(item=>{
                item.onRejected();
            })
        }
        try {
            executor(_resolve, _reject);
        } catch (err) {
            // 如果有异常,将状态更新为失败,失败的值为异常信息
            _reject(err);
        }
    }

    // 将第二个参数(对象)合并至Promise.prototype对象中。
    Object.assign(Promise.prototype, {
        // 1- 接收成功与失败回调函数
        // 2- 返回的是一个Promise实例
        // 3- onResolved成功回调,默认值为value=>value;
        // 4- onRejected失败回调,默认值为reason=>{throw reason};
        then(onResolved, onRejected) {
            // onResolved成功回调,默认值为value=>value;
            if (!(onResolved instanceof Function)) onResolved = value => value;
            //onRejected失败回调,默认值为reason=>{throw reason};
            if (!(onRejected instanceof Function)) onRejected = reason => {
                throw reason
            };
            return new Promise((resolve, reject) => {
                // callback是成功或失败回调
                const _common = function (callback) {
                    setTimeout(()=>{
                        try {
                            // value是成功回调返回结果
                            const value = callback(this.result);
                            // 判断是否为Promise实例
                            if (value instanceof Promise) {
                                value.then(resolve, reject);
                            } else {
                                // 非Promise实例
                                resolve(value);
                            }
                        } catch (err) {
                            reject(err);
                        }
                    })

                }
                // 判断状态为成功,调用成功回调
                if (this.state === "fulfilled") _common.call(this, onResolved);
                else if (this.state === "rejected") _common.call(this, onRejected);
                else {
                    this.callbackFn.push({
                        onResolved: _common.bind(this, onResolved),
                        onRejected: _common.bind(this, onRejected)
                    })
                }
            })
        },
        catch(onRejected){
            return this.then(undefined,onRejected);
        }
    })
    Promise.resolve = function(value){
        // 判断接收的参数是否为Promise实例,如果是直接返回
        if(value instanceof Promise){
            return value;
        }else{
            // 如果不是,创建一个新的Promise,状态为成功,值为value;
            return new Promise(resolve=>{
                resolve(value);
            })
        }
    }
    Promise.reject = function(value){
        // 返回失败的Promise,失败值为接收的value
        return new Promise((resolve,reject)=>{
            reject(value);
        })
    }
    // 1- 接收的是数组,返回的是Promise
    Promise.all = function(promiseArr){
        let index = 0;
        let successArr = new Array(promiseArr.length);
        return new Promise((resolve,reject)=>{
            promiseArr.forEach((value,i)=>{
                value.then(v=>{
                    index++;
                    successArr[i] = v;
                    if(index === promiseArr.length){
                        resolve(successArr);
                    }
                },s=>{
                    // 返回Promise的状态设置失败
                    reject(s);
                })
            })
        })
    }
    Promise.race = function(promiseArr){
        return new Promise((resolve,reject)=>{
            promiseArr.forEach(value=>{
                // value.then(v=>{
                // 	resolve(v);
                // },s=>{
                // 	reject(s);
                // })
                value.then(resolve,reject);
            })
        })
    }
    window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(100)
    },100)
})
const p2 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject(200)
    },50)
})
const p3 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(300)
    },200)
})
const p4 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(400)
    },100)
})
// race:返回的是Promise实例,谁先执行完就与谁的状态以及值相同。
const p = Promise.race([p1,p2,p3,p4]);
console.log(p);

15.24 class版本实现Promise

js
(function (window) {
	// 1-将之前构造函数体内的语句放置到constructor函数中
	// 2-将之前prototype的属性直接放置到Promise中
	class Promise{
		static resolve(value){
			// 判断接收的参数是否为Promise实例,如果是直接返回
			if(value instanceof Promise){
				return value;
			}else{
				// 如果不是,创建一个新的Promise,状态为成功,值为value;
				return new Promise(resolve=>{
					resolve(value);
				})
			}
		}
		static reject(value){
			// 返回失败的Promise,失败值为接收的value
			return new Promise((resolve,reject)=>{
				reject(value);
			})
		}
		static all(promiseArr){
			let index = 0;
			let successArr = new Array(promiseArr.length);
			return new Promise((resolve,reject)=>{
				promiseArr.forEach((value,i)=>{
					value.then(v=>{
						index++;
						successArr[i] = v;
						if(index === promiseArr.length){
							resolve(successArr);
						}
					},s=>{
						// 返回Promise的状态设置失败
						reject(s);
					})
				})
			})
		}
		static race(promiseArr){
			return new Promise((resolve,reject)=>{
				promiseArr.forEach(value=>{
					// value.then(v=>{
					// 	resolve(v);
					// },s=>{
					// 	reject(s);
					// })
					value.then(resolve,reject);
				})
			})
		}
		constructor(executor) {
			this.state = "pending";// 初始状态
			this.result = undefined;// 初始值
			this.callbackFn = [];
			// _resolve函数将状态更新为成功,成功值为接收的value
			const _resolve = value => {
				// 如果状态已经更改,直接跳出函数体
				if (this.state !== "pending") return;
				this.state = "fulfilled";// 状态更新为成功
				this.result = value;// 更新成功值
				this.callbackFn.forEach(item=>{
					item.onResolved();
				})
			}
			// _reject函数将状态更新为失败,失败值为接收的value
			const _reject = value => {
				// 如果状态已经更改,直接跳出函数体
				if (this.state !== "pending") return;
				this.state = "rejected";// 状态更新为失败
				this.result = value;// 更新失败值
				this.callbackFn.forEach(item=>{
					item.onRejected();
				})
			}
			try {
				executor(_resolve, _reject);
			} catch (err) {
				// 如果有异常,将状态更新为失败,失败的值为异常信息
				_reject(err);
			}
		}
		then(onResolved, onRejected) {
			// onResolved成功回调,默认值为value=>value;
			if (!(onResolved instanceof Function)) onResolved = value => value;
			//onRejected失败回调,默认值为reason=>{throw reason};
			if (!(onRejected instanceof Function)) onRejected = reason => {
				throw reason
			};
			return new Promise((resolve, reject) => {
				// callback是成功或失败回调
				const _common = function (callback) {
					setTimeout(()=>{
						try {
							// value是成功回调返回结果
							const value = callback(this.result);
							// 判断是否为Promise实例
							if (value instanceof Promise) {
								value.then(resolve, reject);
							} else {
								// 非Promise实例
								resolve(value);
							}
						} catch (err) {
							reject(err);
						}
					})
					
				}
				// 判断状态为成功,调用成功回调
				if (this.state === "fulfilled") _common.call(this, onResolved);
				else if (this.state === "rejected") _common.call(this, onRejected);
				else {
					this.callbackFn.push({
						onResolved: _common.bind(this, onResolved),
						onRejected: _common.bind(this, onRejected)
					})
				}
			})
		}
		catch(onRejected){
			return this.then(undefined,onRejected);
		}
	}
	window.Promise = Promise;
})(window);
js
const p1 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(100)
    },100)
})
const p2 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        reject(200)
    },50)
})
const p3 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(300)
    },200)
})
const p4 = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        resolve(400)
    },100)
})
// race:返回的是Promise实例,谁先执行完就与谁的状态以及值相同。
const p = Promise.race([p1,p2,p3,p4]);
console.log(p);

Released under the MIT License.