一、准备工作
在学习promise前,我们先了解几个基础概念。
1. 高阶函数扩展方法
// 核心代码
function core(...args) {
console.log('core', args);
}
// 给core增加额外逻辑,但是不改变原有核心代码
Function.prototype.before = function(cb) {
// this => core
return (...args) => {
cb();
this(...args);
}
}
let newCore = core.before(() => {
console.log('before');
})
newCore('a', 'b');
// before
// core ['a', 'b']
函数定义的作用域和执行的作用域不在同一个,肯定会出现闭包
function a() {
function b() {
}
}
b() // b函数在a函数作用域外执行,a不会被销毁
2. 函数柯里化
// 记录传入的参数,并且和函数的参数个数做比较,参数个数一致,执行函数
function curring(fn) {
const inner = (args = []) => {
return args.length >= fn.length ? fn(...args) : (...userArgs) => inner([...args, ...userArgs]);
}
return inner();
}
function sum(a, b, c, d) {
return a + b + c + d;
}
let sum1 = curring(sum);
let sum2 = sum1(1);
let sum3 = sum2(2, 3);
let result = sum3(4);
console.log(result); // 10
柯里化的应用:数据类型判断
function curring(fn) {
const inner = (args = []) => {
return args.length >= fn.length ? fn(...args) : (...userArgs) => inner([...args, ...userArgs]);
}
return inner();
}
function isType(typing, val) {
return Object.prototype.toString.call(val) === `[object ${typing}]`;
}
let util = {};
['String', 'Number', 'Boolean', 'Null', 'Undefined'].forEach(type => {
util[`is${type}`] = curring(isType)(type);
})
console.log(util.isString('abc'));
3. compose函数
function addPrefix(str) {
return '$' + str;
}
function len(str) {
return str.length;
}
function sum(a, b) {
return a + b
}
const compose = (...fns) => {
return fns.reduce(function(a, b) {
return function (...args) {
return a(b(...args));
}
})
}
let final = compose(addPrefix, len, sum);
const r = final('a', 'b');
console.log(r); // $2
4. 发布订阅模式,解决异步并发问题
class Event {
constructor() {
this._events = [];
}
on(fn) {
this._events.push(fn);
}
emit(data) {
this._events.forEach(fn => fn(data));
}
}
function EventEmitter() {
this._events = {};
}
EventEmitter.prototype.on = function (eventName, callback) {
// 实例上可能没有events,没有我们就给他加一个
if (!this._events) {
this._events = {};
}
if (this._events[eventName]) {
this._events[eventName].push(callback);
} else {
this._events[eventName] = [callback];
}
}
EventEmitter.prototype.once = function (eventName, callback) {
// AOP切片,触发之后就移除
const one = () => {
callback();
this.off(eventName, callback);
}
one.l = callback; // 为了避免用户使用时,刚once了,立刻又off的情况(这种情况下不执行)
this.on(eventName, one);
}
EventEmitter.prototype.emit = function (eventName, ...args) {
this._events[eventName].forEach(fn => {
fn(...args);
})
}
EventEmitter.prototype.off = function (eventName, callback) {
if (this._events && this._events[eventName]) {
// off的时候,将on绑定的和once绑定的对应事件名都移除
this._events[eventName] = this._events[eventName].filter(fn => fn !== callback && fn.l !== callback);
}
}
module.exports = EventEmitter;
function Boy() { }
// 原型链继承
Boy.prototype.__proto__ = EventEmitter.prototype;
// Object.setPrototypeOf(Boy.prototype, EventEmitter.prototype);
// Boy.prototype = create(EventEmitter.prototype);
// function create(proto) {
// function Fn() { }
// Fn.prototype = proto;
// return new Fn();
// }
let boy = new Boy();
boy.on('xxx', (y) => {
console.log(111, y);
})
boy.on('xxx', (y) => {
console.log(222, y);
})
boy.once('yyy', () => {
console.log(333);
})
setTimeout(() => {
boy.emit('xxx', 'yyy')
boy.emit('yyy');
boy.emit('yyy')
}, 1000)
5. 观察者模式
// 被观察者
class Subject {
constructor(name) {
this.name = name;
this.state = 'happy';
this.observers = [];
}
// 被观察者要收集观察者,后续状态改变,通知观察者
attach(o) {
this.observers.push(o);
}
setState(newState) {
this.state = newState;
this.observers.forEach(o => o.update(this.name, newState));
}
}
// 观察者
class Observer {
constructor(name) {
this.name = name;
}
update(baby, state) {
console.log(this.name + ',' + baby + '现在' + state);
}
}
let baby = new Subject('xiaoming');
let dad = new Observer('dad');
let mam = new Observer('mom');
baby.attach(dad);
baby.attach(mam);
baby.setState('crying');
二、Promise
Promise
解决了什么问题:
- 链式调用解决嵌套回调的问题。
- 同步并发问题
- 多个异步处理问题
1. 基础promise
// 1. promise是一个类,使用时new
// 2. 使用promise时,传入executor执行器,次函数是立即执行的。
// 3. executor函数接收两个参数,resolve和reject,分别更新当前promise为成功或失败状态
// 4. promise有三种状态,pending, fulfilled, rejected状态变化后不能更改,不可逆。
// 5. 抛出错误,状态变为rejected。
// 6. 每个promise实例都有一个then方法,then是微任务,异步的。
const Promise = require('./src/1.promise.js');
let promise = new Promise((resolve, reject) => {
resolve('成功');
// new Error('xxx');
})
promise.then((val) => {
console.log('success', val);
}, (reason) => {
console.log('err', reason);
})
// 1.promise.js
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined; // 成功的数据
this.reason = undefined; // 失败的数据
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
}
}
try {
executor(resolve, reject);
} catch(e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value);
}
if (this.status === REJECTED) {
onRejected(this.reason);
}
}
}
module.exports = Promise;
2. 异步promise
如果在我们延迟几秒resolve
,怎么处理呢?
当调用then
方法时,promise
的状态可能是pending
,此时需要把成功和失败回调先存起来,等待状态变更后,再执行onFullFilled
或onRejected
(发布订阅)。
const Promise = require('./src/2.promise.js');
let promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 2000)
})
promise.then((val) => {
console.log('success', val);
}, (reason) => {
console.log('err', reason);
})
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined; // 成功的数据
this.reason = undefined; // 失败的数据
+ this.onResolvedCallbacks = [];
+ this.onRejectedCallbacks = [];
const resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 发布
+ this.onResolvedCallbacks.forEach(fn => fn());
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 发布
+ this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch(e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
// 同步执行
if (this.status === FULFILLED) {
onFulfilled(this.value);
}
if (this.status === REJECTED) {
onRejected(this.reason);
}
// 有定时器的情形,先保存起来,resolve的时候依次调用(订阅)
+ if (this.status === PENDING) {
+ this.onResolvedCallbacks.push(() => { //AOP
+ // todo...
+ onFulfilled(this.value);
+ });
+ this.onRejectedCallbacks.push(() => {
+ onRejected(this.reason);
+ });
+ }
}
}
module.exports = Promise;
3. 链式调用
Promise
链式调用,当调用then
方法后,会返回一个新的Promise
。
// 利用x的值来判断是调用promise2的resolve还是reject
function resolvePromise(promise2, x, resolve, reject) {
// 1. x的值是promise2
if (promise2 === x) {
return reject(new TypeError('类型错误'));
}
// 2. 兼容别人的promise,核心就是判断如果是promise就调then,不是promise就直接返回
// 1) 对象或者函数,有可能是promise
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try { // 有可能then方法是通过defineProperty来实现的,取值是可能会发生异常
let then = x.then;
if (typeof then === 'function') { // 认为是promise了
then.call(x, y => { // 为什么不直接x.then这么写呢?因为这样写会触发getter,可能会发生异常
resolve(y);
}, r => {
reject(r);
});
} else {
resolve(x);
}
} catch(e) {
reject(e);
}
// 2)肯定不是promise,是普通值。直接放到promise2.resolve中
} else {
resolve(x);
}
}
// then方法
then(onFulfilled, onRejected) {
// then调用后,返回一个新promise
let promise2 = new Promise((resolve, reject) => {
// 直接成功或失败
if (this.status === FULFILLED) {
setTimeout(() => { // 加定时器,异步的目的是拿到promise2
try {
let x = onFulfilled(this.value);
// x有可能是promise,如果是promise需要看下这个promise是成功还是失败,成功则把成功的结果调用promise2的resolve传递进去。
// 总结:x的值决定是调用promise2的resolve还是reject,如果是promise则取他的状态,如果是普通值,则直接调用resolve;
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
}
// 有定时器的情形,先保存起来,resolve的时候依次调用(订阅)
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
})
return promise2;
}
1)情形一:then中方法返回的是一个普通值(不是promise)的情况,会作为外层下一次then的成功结果。
let promise = new Promise((resolve) => {
resolve('ok');
}).then((data) => {
return 1;
}, err => {
console.log('err', err);
}).then((data) => {
console.log('成功', data); // '成功' 1
}, err => {
console.log('err', err);
})
2)情形二:then中方法执行出错,会走到外层下一次then的失败结果
let promise = new Promise((resolve) => {
resolve('ok');
}).then((data) => {
throw new Error('出错'); // 抛错
}, err => {
console.log('err', err);
}).then((data) => {
console.log('成功', data);
}, err => {
console.log('err', err);// 'err' '出错'
})
3)情形三:如果then中方法返回的是一个promise对象,此时会根据promise的结果来处理是走成功还是失败
let promise2 = new Promise((resolve) => {
resolve(1);
}).then((data) => {
return new Promise((resolve, reject) => { // x 可能是promise
setTimeout(() => {
resolve('ok');
// reject('错误');
}, 1000)
})
})
promise2.then((data) => {
console.log('成功', data); // 成功 'ok'
}, err => {
console.log('err', err);
})
4. 嵌套promise的处理
// 嵌套promise
let promise2 = new Promise((resolve) => {
resolve(1);
}).then((data) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(new Promise((resolve, reject) => { // resolve的还是一个promise
setTimeout(() => {
resolve('ok');
}, 1000)
}));
}, 1000)
})
})
promise2.then((data) => {
console.log('成功', data); // 成功 ok
}, err => {
console.log('err', err);
})
怎么处理呢?
// 利用x的值来判断是调用promise2的resolve还是reject
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('类型错误'));
}
// 1) 对象或者函数,有可能是promise
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
then.call(x, y => {
+ resolvePromise(promise2, y, resolve, reject); // 嵌套promise的情况:resolve的值还是promise
}, r => {
reject(r);
});
} else {
resolve(x);
}
} catch(e) {
reject(e);
}
// 2)肯定不是promise,是普通值。直接放到promise2.resolve中
} else {
resolve(x);
}
}
5. 值得穿透,怎么实现
// 值得穿透
new Promise((resolve) => {
resolve('ok');
}).then().then().then((data) => {
console.log('成功', data); // 成功 ok
}, err => {
console.log('err', err);
})
new Promise((resolve, reject) => {
reject('err');
}).then().then().then((data) => {
console.log('成功', data);
}, err => {
console.log('err', err); // err err
})
then
的参数是可选的,不传就给他一个默认的函数。
then(onFulfilled, onRejected) {
// 穿透问题
+ onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
+ onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// then调用后,返回一个新promise
let promise2 = new Promise((resolve, reject) => {
...
})
return promise2;
}
到这里,满足PromiseA+规范的promise就完成了,我们再看看规范外应用比较广泛的一些内容。
6. 延迟对象
// 延迟对象,帮我们减少一次套用
Promise.deferred = function() {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
}
// 正常写法
function readFile(filePath, encoding) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, encoding, (err, data) => {
if (err) return inject(err);
resolve(data);
})
})
}
// 使用延迟套用的写法
function readFile(filePath, encoding) {
let dfd = Promise.deferred;
fs.readFile(filePath, encoding, (err, data) => {
if (err) return dfd.inject(err);
dfd.resolve(data);
})
return dfd.promise;
}
7. promise直接resolve一个promise
new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
resolve(100)
}))
}).then(data => {
console.log('成功', data); // 成功 100
})
在resolve
时,判断如果是promise
的实例,则直接调用promise的then方法。
class Promise {
constructor(executor) {
...
const resolve = (value) => {
// 直接resolve一个promise
+ if (value instanceof Promise) {
+ return value.then(resolve, reject);
+ }
}
const reject = (reason) => {
...
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
...
}
}
8. promise几个静态方法
1)Promise.resolve、Promise.reject、catch
// Promise.resolve() 方法
Promise.resolve('ok').then((data) => {
console.log('成功', data); // 成功 ok
})
// Promise.reject() 方法
Promise.reject(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
})).then((data) => {
console.log('成功', data);
}, err => {
console.log('err', err); // err
})
// catch
Promise.reject(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 1000);
})).then((data) => {
console.log('成功', data);
}).catch(err => {
console.log('err', err); // err
})
实现原理如下:
class Promise {
then(onFulfilled, onRejected) {
...
}
catch(errorFn) {
return this.then(null, errorFn);
}
static resolve(value) {
return new Promise((resolve, reject) => {
resolve(value);
})
}
static reject(value) {
return new Promise((resolve, reject) => {
reject(value);
})
}
}
2) Promise.all方法
同一时刻拿到多个异步请求的结果。
Promise.all
有个缺点:只要其中一个失败了,整个Promise
就失败了。
Promise.all([1, 2, 3, new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
}, 2000)
})]).then((data) => {
console.log('成功', data); // 成功 [1, 2, 3, 'ok']
}).catch(e => {
console.log('失败', e);
})
实现原理如下:
// Promise.all
Promise.all = function(promises) {
return new Promise((resolve, reject) => {
let result = [];
let times = 0;
const processSuccess = (index, val) => {
result[index] = val;
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (p && typeof p.then === 'function') {
p.then((data) => {
processSuccess(i, data);
}, reject);
} else {
processSuccess(i, p);
}
}
})
}
3) Promise.race
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
}, 2000)
})
Promise.race = function(promises) {
return new Promise((resolve, reject) => {
for (let i = 0; i< promises.length; i++) {
let p = promises[i];
if (p && typeof p.then === 'function') {
p.then(resolve, reject)
} else {
resolve(p)
}
}
})
}
Promise.race([p1, p2]).then((data) => {
console.log(data);
}, (err) => {
console.log(err);
})
Promise.race
的使用场景:图片加载、请求加载超时、脚本加载超时处理(超时后,即使结果返回也不采用成功的结果了)。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 2000)
})
function wrap(p1) {
let abort;
let p = new Promise((resolve, reject) => {
abort = reject;
});
let p2 = Promise.race([p, p1]);
p2.abort = abort;
return p2;
}
let p2 = wrap(p1);
p2.then((data) => {
console.log(data);
}, (err) => {
console.log(err);
});
setTimeout(() => {
p2.abort('超过1s了');
}, 1000);
4) Promise.prototype.finally
Promise.prototype.finally
原型方法,无论状态如何都会执行,而且可以继续向下执行。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
// reject('失败')
}, 3000);
}).finally((data) => {
console.log('finally', data); // finally undefined => finally接受不到参数,但是可以把resolve的返回值透传下去
}).then((data) => {
console.log('resolve', data); // resolve 成功
}).catch((data) => {
console.log('reject', data); // reject 失败
})
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
// reject('失败')
}, 3000);
}).finally((data) => {
console.log('finally', data); // finally undefined
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('xxx');
// reject('yyy')
}, 2000);
})
}).then((data) => {
console.log('resolve', data); // resolve 成功
}).catch((data) => {
console.log('reject', data); // reject yyy
})
finally
的特点:
- 无论状态为成功还是失败,都可以继续往下执行。
finally
没有参数,会把excutor
中的返回值,透传下去。如果是resolve
,则透传给then
,reject
则透传给catch
。finally
返回一个promise
时,如果promise
是resolve
了值,则忽略。传递给then
的仍旧是excutor
的resolve
值。如果promise
是reject
了值,则将reject
的值传递给catch
。
实现一个Promise.prototype.finally
Promise.prototype.finally = function(cb) {
// then是为了等待里层promise执行完
return this.then((data) => {
// Promise.resolve实现等待效果,等待cb执行完,然后将excutor中的值传递下去
return Promise.resolve(cb()).then(() => data); // Promise.resolve保证promise执行完毕
}, (err) => {
return Promise.resolve(cb()).then(() => { throw err });
})
}
5) Promise.allSettled
不管是成功还是失败,会得到所有结果,不会走catch方法。
// Promise.allSettled
Promise.allSettled = function(promises) {
return new Promise((resolve, reject) => {
let result = [];
let times = 0;
const processSuccess = (index, val) => {
result[index] = val;
if (++times === promises.length) {
resolve(result);
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (p && typeof p.then === 'function') {
p.then((data) => {
processSuccess(i, { status: 'fulfilled', value: data });
}).catch((err) => {
processSuccess(i, { status: 'rejected', reason: err });
})
} else {
processSuccess(i, p);
}
}
})
}
Promise.allSettled([1, 2, 3, new Promise((resolve, reject) => {
setTimeout(() => {
reject('错误');
}, 2000)
})]).then((data) => {
console.log('成功', data); // 成功 [ 1, 2, 3, { status: 'rejected', reason: '错误' } ]
}).catch(e => {
console.log('失败', e);
})
6) Promise.any
如果其中一个成功了,就走成功,返回的是第一个成功的值。都失败了才会走失败。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功')
}, 1000)
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
}, 2000)
})
Promise.any = function(promises) {
return new Promise((resolve, reject) => {
let result = [];
let times = 0;
const processSuccess = (index, val) => {
result[index] = val;
if (++times === promises.length) {
reject(result);
}
}
for (let i = 0; i < promises.length; i++) {
let p = promises[i];
if (p && typeof p.then === 'function') {
p.then((data) => {
resolve(data);
}).catch(err => {
processSuccess(i, err)
});
} else {
resolve(p);
}
}
})
}
Promise.any([p1, p2]).then((data) => {
console.log(data); // 成功
}, (err) => {
console.log(err);
})
7) promisify
promisify
,主要功能是将一个异步的方法转化成promise
的形式。主要给node
来使用的。
回调函数的参数永远第一个是error
。
function promisify(readFile) {
return function (...args) {
return new Promise((resolve, reject) => {
readFile(...args, (err, data) => {
if (err) return reject(err);
resolve(data);
})
})
}
}
const fs = require('fs');
let readFile = promisify(fs.readFile);
readFile('./.gitignore', 'utf8').then((data) => {
console.log(data);
})
8) promisifyAll
把对象里的方法都转成promise
的形式。
function promisifyAll(obj) {
let o = {};
for (let key in obj) {
if (typeof obj[key] === 'function') {
o[key+'Promise'] = promisify(obj[key])
}
}
return o;
}
const fs = require('fs');
let newFs = promisifyAll(fs);
newFs.readFilePromise('./.gitignore', 'utf8').then((data) => {
console.log(data);
})
三、generator函数
generator
函数核心是通过switch case
实现的。
function* read() {
console.log('first');
yield 1;
console.log('second');
yield 2;
console.log('third');
yield 3;
}
let it = read(); // 迭代器
it.next(); // first
it.next(); // second
it.next(); // third
实现原理:
let regeneratorRuntime = {
wrap(iteratorFn) {
const context = {
prev: 0,
next: 0,
done: false,
stop() {
this.done = true;
}
}
// 迭代器
let it = {};
it.next = function() {
let value = iteratorFn(context);
return {
value,
done: context.done
}
}
return it;
}
}
function read() {
return regeneratorRuntime.wrap(function read$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
console.log('first');
_context.next = 3;
return 1;
case 3:
console.log('second');
_context.next = 6;
return 2;
case 6:
console.log('third');
_context.next = 9;
return 3;
case 9:
case "end":
return _context.stop();
}
}
});
}
let it = read(); // 迭代器
{
let { value, done } = it.next(); // first
console.log(value, done); // 1 false
}
{
let { value, done } = it.next(); // second
console.log(value, done); // 2 false
}
{
let { value, done } = it.next(); // third
console.log(value, done); // 3 false
}
{
let { value, done } = it.next();
console.log(value, done); // undefined done
}
generator
next
传参的情形:
function* read() {
var a = yield 1;
console.log(a);
var b = yield 2;
console.log(b);
var c = yield 3;
console.log(c);
}
let it = read(); // 迭代器
{
let {value, done} = it.next('xxx'); // 第一个传参也没用,没做处理,设计如此
console.log(value, done); // 1 false
}
{
let {value, done} = it.next('aaa'); // aaa
console.log(value, done); // 2 false
}
{
let {value, done} = it.next('bbb'); // bbb
console.log(value, done); // 3 false
}
{
let {value, done} = it.next('ccc'); // ccc
console.log(value, done); // undefined done
}
执行流程:
实现原理:
let regeneratorRuntime = {
wrap(iteratorFn) {
const context = {
prev: 0,
next: 0,
sent: '',
done: false,
stop() {
this.done = true;
}
}
// 迭代器
let it = {};
it.next = function (v) {
context.sent = v; // next传参
let value = iteratorFn(context);
return {
value,
done: context.done
}
}
return it;
}
}
function read() {
return regeneratorRuntime.wrap(function read$(_context) {
while (1) {
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 = read(); // 迭代器
{
let { value, done } = it.next('xxx'); // 从实现上可以看到case 0里没有用到context.sent,所以第一个传参被忽略
console.log(value, done); // 1 false
}
{
let { value, done } = it.next('aaa'); // aaa
console.log(value, done); // 2 false
}
{
let { value, done } = it.next('bbb'); // bbb
console.log(value, done); // 3 false
}
{
let { value, done } = it.next('ccc'); // ccc
console.log(value, done); // undefined true
}
四、generator+co实现异步迭代
const fs = require('fs');
const util = require('util');
// const co = require('co');
let readFile = util.promisify(fs.readFile);
function co(it) {
return new Promise((resolve, reject) => {
// 异步迭代用递归
function next(data) {
let { value, done } = it.next(data);
if (done) {
resolve(value);
} else {
Promise.resolve(value).then(next, reject);
}
}
next();
})
}
function* read() {
let data = yield readFile('./a.txt', 'utf8');
data = yield readFile(data, 'utf8');
return data;
}
// 不用co
// let it = read();
// let { value, done } = it.next();
// value.then((data) => { // data => b.txt
// let { value, done } = it.next(data);
// value.then(data => { // data => b
// let { value, done } = it.next(data);
// console.log(value, done);
// })
// })
// 用co
co(read()).then(data => {
console.log(data); // b
}).catch(err => {
console.log(err);
})
五、async await
async
是generator
+ co
的语法糖,await
返回的是一个promise
。
// async await
const fs = require('fs');
const util = require('util');
let readFile = util.promisify(fs.readFile);
async function read() {
let data = await readFile('./a.txt', 'utf8');
data = await readFile(data, 'utf8');
return data;
}
read().then(data => {
console.log(data); // b
})
六、经典面试题
Promise.resolve().then(() => {
console.log('then1');
return Promise.resolve().then(()=>{
console.log('then1-1');
return Promise.resolve();
}).then(()=>{
console.log('then1-2')
})
})
.then(() => {
console.log('then2');
})
.then(() => {
console.log('then3');
})
.then(() => {
console.log('then4');
})
.then(() => {
console.log('then5');
})
then1
then1-1
then1-2
then2
then3
then4
then5
promise.resolve.then
中return
了promise
,就会等待promise
执行完成后,继续往下执行。
Promise.resolve().then(() => { // ①
console.log('then1');
Promise.resolve().then(()=>{ // ②
console.log('then1-1');
return Promise.resolve(); // ④ x.then
}).then(()=>{ // ⑥
console.log('then1-2')
})
})
.then(() => { // ③
console.log('then2');
})
.then(() => { // ⑤
console.log('then3');
})
.then(() => { // ⑦
console.log('then4');
})
.then(() => { // ⑧
console.log('then5');
})
then1
then1-1
then2
then3
then4
then1-2
then5
我们先按照PromiseA+规范分析一下:
第一轮:先把promise.resolve().then的回调,即①放入执行栈。往下执行
第二轮:打印then1
,将②放入微任务队列,将③放入微任务队列,执行②中promise.resolve().then,打印then1-1
。执行③中then回调,打印then2
。
第三轮:return Promise.resolve();
then中return一个promise,相当于x.then。将④放入微任务队列。接下来将⑤放入微任务队列。
第四轮:执行④,又是一个.then,所以将⑥放入微任务队列。执行⑤,打印then3
。
第五轮:执行⑥,打印then1-2
。
第六轮:⑥执行完毕后,将⑦和⑧依次放入微任务队列,依次执行。打印then4
和then5
。
我们打印的值是:then1 then1-1 then2 then3 then1-2 then4 then5
为什么和浏览器中打印表现不一致呢?因为我们是按照promiseA+规范分析的,浏览器还有自己的规定,如果return了一个promise,会额外开辟一个异步方法,相当于多了依次then。