- Promise是一个类,使用的时候需要new Promise来产生一个promise实例
- 构造函数中需要传递一个参数 executor
- xecutor函数中有两个参数 resolve(value) reject(reason)
- 调用resolve会让promise变成成功 调用reject会变成失败 pending等待态 fulfilled 成功态 rejected失败态
- 一但状态发生变化后不能再修改状态
- 每个promise实例都有一个then方法,会有两个参数 onfulfilled, onrjected
- 如果不调用resolve此时promise不会成功也不会失败 (如果发生异常也会认为是失败)
- resolve之后 不能reject 相反也是
- executor是立刻执行的
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('ok')
},100000)
})
promise.then((value) => {
console.log('成功1', value)
}, (reason) => {
console.log('失败1', reason)
});
promise.then((value) => {
console.log('成功2', value)
}, (reason) => {
console.log('失败2', reason)
});
promise链式调用
-
返回的是一个普通值(非promise的值)
- 返回的是一个普通值(非promise的值)这个值会被传到外层then的下一个then的成功中去
- 没有返回值(抛错了),会执行外层的then的下一个then的失败
-
返回的是一个promise
- 会去解析返回的promise将解析后的值,传递到成功或者失败中(看这个promise是什么状态)
- 什么时候会失败
- 抛错走下一次的失败
- 返回的是失败的promise会走失败
-
promise为了能扭转状态 而且还要保证promise状态变化后不可以更改。 返回一个全新的promise
实现promise
promise.js
console.log('my promise run')
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED'
// 此函数主要的目的是判断x 是不是promise
// 规范中说明 我们的promise可以和别人的promise互通
function resolvePromise(x, promise2, resolve, reject) {
// 用x 的值来决定promise2 是成功还是失败 (resolve,reject)
if (x === promise2) {
return reject(new TypeError('[TypeError: Chaining cycle detected for promise #<Promise>] error'))
}
// promise实例要么是对象要么是函数
if ((typeof x === 'object' && x !== null) || (typeof x === 'function')) {
let called = false
try {
let then = x.then;// 看是否有then方法
if (typeof then === 'function') {
// 不用每次都取值了,直接用上次取到的结果
then.call(x, (y) => { // 别人家的promise
if (called) return
called = true
resolvePromise(y,promise2,resolve,reject)
}, (r) => {
if (called) return
called = true
reject(r)
})
} else {
resolve(x); // {then:{}} | {} | function
}
} catch (e) { // 别人家的promise
if (called) return
called = true
reject(e); // 取值出错
}
} else { // 说明x是一个普通值
resolve(x); // 普通值直接向下传递即可
}
}
class Promise {
constructor(executor) {
// 默认promise的状态
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolveCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
// 只有pending状态才可以修改状态
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
this.onResolveCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED;
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try { // 如果executor执行发生异常 就默认等价reject方法
executor(resolve, reject);
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
// then方法中如果没有传递参数 那么可以透传到下一个then中
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected:(reason) => {
throw reason
}
let promise2 = new Promise((resolve, reject) => {
// ...
if (this.status === FULFILLED) {
process.nextTick(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
console.log(e)
reject(e)
}
})
}
if (this.status === REJECTED) {
process.nextTick(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) { // 调用then的时候promise没成功也没失败
this.onResolveCallbacks.push(() => {
// todo...
process.nextTick(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
process.nextTick(() => {
try {
let x = onRejected(this.reason)
resolvePromise(x, promise2, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
}
Promise.deferred = function () {
const dfd = {}
dfd.promise = new Promise((resolve, reject) =>{
dfd.resolve = resolve
dfd.reject = reject
})
return dfd;
}
// npm install promises-aplus-tests -g
module.exports = Promise
静态方法
Promise.resolve
- Promise.resolve 是ECMAScript自己实现的(为了能快速创建promise并且具备等待效果)
- romise.resolve 有一个特点就是会产生一个新的promise, 如果你传入的值是一个promise
- Promise.resolve 可以解析传入的promise 具备等待效果
Promise.reject
- 不具备等待
catch
- 错误可以通过catch来捕获,实际上是then(第一个参数为null)
Promise.all
- Promise.all 等待所有的promise都成功才成功,有一个失败就失败了
// 都成功才成功,有一个失败就失败了
Promise.all = function (values) {
return new Promise((resolve, reject) => {
let idx = 0;
let result = [];
values.forEach((item,i) => {
Promise.resolve(item).then((val) => {
result[i] = val; // 数组的长度不准确, 用索引映射成功的结果
if (++idx === values.length) {
resolve(result)
}
},reject)// 如果任何一个promise失败了那么all就失败了
})
})
}
Promise.race
- 哪个结果快就用谁的,用它来中断成功的结果
Promise.race = function (values) {
return new Promise((resolve, reject) => {
values.forEach((item,i) => {
Promise.resolve(item).then(resolve,reject)// 如果任何一个promise失败了那么all就失败了
})
})
}
超时处理
- 超时处理:由于promise.race中有一个失败了就失败了,所以要想让一个成功的promise,延迟x秒失败的话,就可以构建一个reject和原有的promsie,放入Promise.race中
// 可以自己构建一个promise,和用户写的放在一起,如果我想让用户的失败,我就让内置的promise失败就可以了
let abort
function withAbort(userPromise) {
let abort;
const internalPromise = new Promise((resolve, reject) => {
abort = reject
})
let p = Promise.race([userPromise,internalPromise])
p.abort = abort
return p
}
let p = new Promise((resolve, reject) => {
// abort = reject;
setTimeout(() => {
resolve(100)
}, 3000)
})
p = withAbort(p)
setTimeout(() => {
p.abort('超时了')
},2000)
p.then(data => {
console.log(data)
}).catch(err => { // 如何让这个promise 走向失败?
console.log(err,'error')
})
Promise.allSettled
es10中提供的,无论成功和失败都要结果
Promise.allSettled()
不会在任何 Promise 被拒绝时中止,并且总是等待所有 Promise 对象都已解决或拒绝后才返回结果
status
:表示 Promise 的状态,可能的值为 “fulfilled”(已解决)或 “rejected”(已拒绝)。value
:如果 Promise 已解决,则为解决值;如果 Promise 已拒绝,则为拒绝原因。
const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'error'));
const promise3 = new Promise((resolve) => setTimeout(resolve, 200, 'resolved'));
Promise.allSettled([promise1, promise2, promise3])
.then((results) => {
results.forEach((result) => {
console.log(result.status); // 输出 "fulfilled", "rejected", "fulfilled"
console.log(result.value); // 输出 3, "error", "resolved"
});
});
Promise.xxx.finally
- 无论成功和失败都要执行的逻辑
// 无论成功和失败都要执行的逻辑
Promise.prototype.finally = function (fn) {
return this.then((val) => {
// Promise.resolve 具备一个功能,就是可以解析传入的promise
return Promise.resolve(fn()).then(()=>val)
}, (r) => {
return Promise.resolve(fn()).then(()=>{throw r})
})
}
Promise.resolve('abc').finally(() => { // 无论成功还是失败都会执行
return new Promise((resolve, reject) => {
setTimeout(()=>{resolve('abcasdasda')},1000)
})
}).then((value) => {
console.log('成功',value)
}).catch((value) => {
console.log('失败',value)
})
// promise 解析过程 一个promise 返回一个promise才会有等待效果,会采用返回的promise的状态作为下一次then的结果
promisify
将遵循 Node.js 回调风格的函数转换为返回 Promise 的函数
只针对node 因为node中函数参数,第一个永远是错误, 基于传递的参数构建promise
function promisify(fn) { // 高阶函数
return (...args) => {
return new Promise((resolve, reject) => {
fn(...args, function (err, data) {
if (err) return reject(err)
resolve(data)
})
})
}
}
function promisifyAll(obj) { // 转化对象中所有的api
for (let key in obj) {
const val = obj[key]
if (typeof val === 'function') {
obj[key] = promisify(val)
}
}
}
generator生成器
- 生成器,在生成的过程中可以暂停,可以自己控制是否继续
- 生成器是用来生成迭代器
- yield的返回值是下一次调用next传递的参数
function* gen() {
try {
let a = yield 1; // js执行是先走等号右边的,遇到yield就停止了
console.log(a)
let b = yield 2;// yield的返回值是下一次调用next传递的参数
console.log(b)
let c = yield 3
console.log(c)
return undefined
} catch (e) {
console.log(e)
}
}
let it = gen(); // iterator 迭代器
console.log(it.next('asdasdasd')); // 第一次调用next方法传递的参数没有任何意义
it.throw('错误'); // 调用了第一次next的时候 可以暂停逻辑,如果觉得这个逻辑有异常后续可以通过throw方法抛出异常
console.log(it.next('abc'));
console.log(it.next('abcd')); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
console.log(it.next()); // { value: 3, done: false }
console.log(it.next()); // { value: 4, done: false }
co模块
co 模块 使用 Generator生成器函数 和promise, 让我们以同步的形式写异步代码
-
co是npm的一个包
function co(it) { return new Promise((resolve, reject) => { // 同步迭代for循环,异步迭代用回调 function next(data) { // koa express let { value, done } = it.next(data); if (!done) { // 如果没完成返回的一定是一个promise Promise.resolve(value).then((data => { next(data) }),reject) } else { resolve(value); // 完成value就是最后的结果 } } next(); }) }
实现generator
generator 的原理就是将一个函数分解成多个 switch case通过指针指向要执行的部分
function wrap(iteratorFn) {
const _context = {
next: 0,
done:false,
sent: undefined,
stop() {
this.done = true;
}
}
return {
next(value) {
_context.sent = value; // 先赋值再去调用方法
let v = iteratorFn(_context); // 执行函数传递上下文
return {value:v,done:_context.done}
},
}
}
function gen() {
var a, b, c;
return wrap(function gen$(_context) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return 1;
case 2:
a = _context.sent;
console.log(a);
_context.next = 6;
return 2;
case 6:
b = _context.sent;
console.log(b);
_context.next = 10;
return 3;
case 10:
c = _context.sent;
console.log(c);
case 12:
case "end":
return _context.stop();
}
});
}
let it = gen();
console.log(it.next())
console.log(it.next('abc'))
console.log(it.next('bcd'))
console.log(it.next('bcd'))
// 实现了一个简易的generator ,generator 的原理就是将一个函数分解成多个 switch case通过指针指向要执行的部分
// function* gen() {
// let a = yield 1;
// console.log(a)
// let b = yield 2;
// console.log(b)
// let c = yield 3;
// console.log(c)
// }
async、await
co+generator 就是async+await
- https://www.babeljs.cn/repl#?browsers=ie%206&build=&builtIns=false&corejs=3.21&spec=false&loose=false&code_lz=IYZwngdgxgBAZgV2gFwJYHsIwE4FNgAmASriAgDbIAUAlDAN4BQMLM5uy8q7EwAtrhgBeGMADuwVJzggAdHkIAxbrioAHYMgAW80unIA3VQH1jBVNl4CANDADkV3LOQAPZHZq27CZHAAcHgDczKzsnMAA5oIi4pLScgoEyuzqmjp4IPpGVKbmlvy4tnAqjp72Pv5BISx4yAiWolHBAL5AA&debug=false&forceAllTransforms=false&modules=false&shippedProposals=false&circleciRepo=&evaluate=false&fileSize=false&timeTravel=false&sourceType=module&lineWrap=true&presets=env%2Creact%2Cstage-0%2Cstage-1%2Cstage-2%2Cflow&prettier=false&targets=&version=7.24.7&externalPlugins=&assumptions=%7B%7D