5.7 all() 实现
Promise对象数组中所有的都为成功返回的Promise对象才成功,有一个失败返回的就为失败。
Promise.all = function (promises) { // 返回一个Promise对象 return new Promise((resolve, reject) => { // 记录状态为成功的promise对象个数 let count = 0; // 保存成功promise对象的结果 let arr = [] for (let i = 0; i < promises.length; i++) { // Promise 对象肯定可以调用 then promises[i].then(v => { // 状态为成功的个数++ count++ // 保证数组中结果集的顺序与传入的promise对象的顺序一样 arr[i] = v // 状态为成功的个数与promise对象数组的个数一样 if (count === promises.length) { resolve(arr) } }, r => { reject(r) }) } }) }
测试:
const p1 = Promise.resolve('OK') const p2 = Promise.resolve( new Promise((resolve, reject) => { resolve('OK~~~') }) ) const p3 = Promise.reject( new Promise((resolve, reject) => { reject('err') }) ) const res1 = Promise.all([p1, p2]) const res2 = Promise.all([p1, p2, p3]) console.log(res1) console.log(res2)
5.8 race()实现
最先改变状态的promise对象的状态为返回的Promise对象的状态,其结果为返回的Promise对象的结果。
Promise.race = function (promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { // 第一个改变状态的promise在其回调函数直接改变返回promise的回调函数 promises[i].then(v => { resolve(v) }, r => { reject(r) }) } }) }
const p1 = Promise.resolve( new Promise((resolve, reject) => { setTimeout(()=>{ resolve('OK~~~') }, 1000) }) ) const p2 = Promise.resolve('OK') const p3 = Promise.reject( new Promise((resolve, reject) => { reject('err') }) ) const res1 = Promise.race([p1, p2, p3]) console.log(res1)
5.9 then方法回调的异步执行
官方的then
const p1 = new Promise((resolve, reject) => { resolve('OK') console.log(111) }) p1.then((v) => { console.log(222) }) console.log(333)
异步任务会在同步任务全部执行完成后才执行
我们的then
修改方法:(原先的回调函数均为同步执行的)将其修改为异步任务
// 状态为成功 if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') { setTimeout(() => { callback(onResolved) }); } // 状态为失败 if (this.PromiseState === 'rejected') { setTimeout(() => { callback(onRejected) })
// 定义resolve函数 function resolve(data) { if (self.PromiseState !== 'pending') return // 状态已经修改直接退出 self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState self.PromiseResult = data // 修改 Promise的结果 PromiseResult setTimeout(() => { self.callback.forEach(item => { // 调用所有的回调函数 item.onResolved(self.PromiseResult) }) }) } // 定义reject函数 function reject(data) { if (self.PromiseState !== 'pending') return // 状态已经修改直接退出 self.PromiseState = 'rejected' // 修改 Promise的状态 PromiseState self.PromiseResult = data // 修改 Promise的结果 PromiseResult setTimeout(() => { self.callback.forEach(item => { // 调用所有的回调函数 item.onRejected(self.PromiseResult) }) }) }
修改完成后
5.10 封装为Promise类
class Promise { constructor(excutor) { // 定义 PromiseState PromiseResult this.PromiseState = 'pending' // 默认状态 pending this.PromiseResult = null // 结果默认为空 const self = this // 将 Promise 对象的 this 保存下来 this.callback = [] // 声明一个数组用于保存回调函数 // 定义resolve函数 function resolve(data) { if (self.PromiseState !== 'pending') return // 状态已经修改直接退出 self.PromiseState = 'fulfilled' // 修改 Promise的状态 PromiseState self.PromiseResult = data // 修改 Promise的结果 PromiseResult setTimeout(() => { self.callback.forEach(item => { // 调用所有的回调函数 item.onResolved(self.PromiseResult) }) }) } // 定义reject函数 function reject(data) { if (self.PromiseState !== 'pending') return // 状态已经修改直接退出 self.PromiseState = 'rejected' // 修改 Promise的状态 PromiseState self.PromiseResult = data // 修改 Promise的结果 PromiseResult setTimeout(() => { self.callback.forEach(item => { // 调用所有的回调函数 item.onRejected(self.PromiseResult) }) }) } // 捕获 excutor 中的异常并进行处理 try { // 调用传参传过来的执行器函数 同步调用 excutor(resolve, reject) } catch (e) { // 处理异常,改变Promise状态为失败,改变结果 reject(e) } } then(onResolved, onRejected) { const self = this // 保存调用then的Promise对象 // 判断失败的回调函数 // 由于报错造成的原因是失败的回调函数为undefined // 所以当失败的回调函数为未定义时候,补充一个失败回调 // 让其报错 if (typeof onRejected !== 'function') { onRejected = reason => { throw reason } } // 没有传递成功的回调函数 // 给一个默认的成功回调函数 if (typeof onResolved !== 'function') { onResolved = value => { return value //将resolve中传递的值,即Promise的结果向后传递 } } // 执行完then()返回一个Promise对象 return new Promise((resolve, reject) => { // 封装函数 function callback(type) { try { const result = type(self.PromiseResult) if (result instanceof Promise) { // 如果是Promise的实例对象 result.then(v => { resolve(v) // 调用成功函数,改变返回的Promise对象为成功 }, r => { reject(r) // 调用失败函数,改变返回的Promise对象为失败 }) } else { resolve(result) } } catch (e) { reject(e) } } // 状态为成功 if (this.PromiseState === 'fulfilled' || this.PromiseState === 'resolved') { setTimeout(() => { callback(onResolved) }); } // 状态为失败 if (this.PromiseState === 'rejected') { setTimeout(() => { callback(onRejected) }); } // 状态为 pending if (this.PromiseState === 'pending') { this.callback.push({ onResolved: function () { callback(onResolved) }, onRejected: function () { callback(onRejected) } }) } }) } catch(onRejected) { // catch 方法中执行的是失败的回调函数 // 与 then 差别为只有失败的回调函数,可以直接使用then return this.then(undefined, onRejected) } // resolve、reject、all、race不属于实例对象,属于类 // 用static进行修饰 static resolve(value) { return new Promise((resolve, reject) => { if (value instanceof Promise) { // 为Promise对象,肯定可以调用then value.then(v => { resolve(v) }, r => { reject(r) }) } else { resolve(value) } }) } static reject(value) { return new Promise((resolve, reject) => { reject(value) }) } static all(promises) { // 返回一个Promise对象 return new Promise((resolve, reject) => { // 记录状态为成功的promise对象个数 let count = 0; // 保存成功promise对象的结果 let arr = [] for (let i = 0; i < promises.length; i++) { // Promise 对象肯定可以调用 then promises[i].then(v => { // 状态为成功的个数++ count++ // 保证数组中结果集的顺序与传入的promise对象的顺序一样 arr[i] = v // 状态为成功的个数与promise对象数组的个数一样 if (count === promises.length) { resolve(arr) } }, r => { reject(r) }) } }) } static race(promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { // 第一个改变状态的promise在其回调函数直接改变返回promise的回调函数 promises[i].then(v => { resolve(v) }, r => { reject(r) }) } }) } }
测试:
const p1 = new Promise((resolve, reject) => { resolve('OK') console.log(111) }) p1.then((v) => { console.log(222) }) console.log(333)
6 async与await
6.1 mdn 文档
6.2 async 函数
- async函数的返回值为 promise 对象
async function f1() { } const res1 = f1() console.log(res1)
- promise 对象的结果由 async 函数执行的返回值决定(与then的规则一样)
返回的为非Promise对象的数据,则函数返回的结果为成功的Promise对象,Promise对象的结果为return的结果
async function f1() { return 123 } const res1 = f1() console.log(res1)
- 返回的为失败的Promise,函数返回的为失败的Promise
async function f1() { return new Promise((resolve, reject)=>{ reject('OK') }) } const res1 = f1() console.log(res1)
- 返回的为成功的Promise,函数返回的为成功的Promise
async function f1() { return new Promise((resolve, reject)=>{ resolve('OK') }) } const res1 = f1() console.log(res1)
- 函数抛出错误,返回的为失败的Promise
async function f1() { throw 'ERROR' } const res1 = f1() console.log(res1)
6.3 await 表达式
- await 右侧的表达式一般为 promise 对象, 但也可以是其它的值,运算相关的也行
- 如果表达式是 promise 对象, await 返回的是 promise 成功的值
async function f() { const p = Promise.resolve('OK') let res = await p console.log(res) } f()
- 如果表达式是其它值, 直接将此值作为 await 的返回值
async function f() { let res = await 20 console.log(res) } f()
- 注意
await 必须写在 async 函数中, 但 async 函数中可以没有 await
await 20;
- 如果 await 的 promise 失败了, 就会抛出异常, 需要通过 try…catch 捕获处理
async function f() { const p = Promise.reject('ERROR') let res = await p console.log(res) } f()
async function f() { const p = Promise.reject('ERROR') try { let res = await p } catch (error) { console.log(error) } } f()
6.4 async与await结合实践 – 读取文件
6.4.1 不基于Promise实现 – 回调地狱
const { log } = require('console') const fs = require('fs') // 会出现data变量名覆盖 fs.readFile('./content.txt', (err, data1) => { if (err) return err fs.readFile('./content.txt', (err, data2) => { if (err) return err fs.readFile('./content.txt', (err, data3) => { if (err) return err log( data1+data2+data3 ) } ) }) })
6.4.2 基于Promise
const { log } = require('console') const fs = require('fs') // util 中的 util.promisify() 可以对读取文件的方法进行封装 const util = require('util') const myReadFile = util.promisify(fs.readFile) // 读取文件 async function read() { let data1 = await myReadFile('./content.txt') let data2 = await myReadFile('./content.txt') let data3 = await myReadFile('./content.txt') log(data1 + data2 + data3) } read()
使用async与await,也便于报错处理,不像fs回调那样每层都要独立的报错处理
const { log } = require('console') const fs = require('fs') // util 中的 util.promisify() 可以对读取文件的方法进行封装 const util = require('util') const myReadFile = util.promisify(fs.readFile) // 读取文件 async function read() { try { let data1 = await myReadFile('./content1111111111111.txt') let data2 = await myReadFile('./content.txt') let data3 = await myReadFile('./content.txt') log(data1 + data2 + data3) } catch (e) { log(e) } } read()