有then方法的对象和函数:promise、thenable
两个值:value reason
异常:exception
promise三种状态和关系
1 pending
初始状态,可以改变
一个promise在resolve和reject之间,处于这个状态
resolve 到 fulfilled
reject 到 rejected
2 fulfilled
最终状态不可改变
resolve之后变成这样的状态
必须有一个value值
3 rejected
最终状态不可改变
reject之后变成这样的状态
必须有一个reason的值
#### then
promise有一个then方法用来访问最终的结果
promise.then(onFulfilled,onrejected)
1、onFulfilled,onrejected 必须是函数类型,否则被忽略
2、onFulfilled 在promise 变成 fulfilled 时,应该调用onFulfilled,参数是value
变成之前,不调用
只能被调用一次,可以设置一个变量控制次数
3、onrejected 在变成 rejected 时,调用 onrejected,参数是reason
4、onFulfilled,onrejected 应该是微任务 queueMicrotask 实现微任务
5、promise状态变成 fulfilled 之后,onfulfilled回调都需要按照then的顺序执行 用数组list执行
promise状态变成 rejected 之后,onrejected回调都需要按照then的顺序执行 用数组list执行
6、then的返回值,返回一个promise
onfulfilled和onrejected执行结果为x,调用resolvePromise方法
如果onfulfilled/onrejected执行抛出异常e,promise2要被reject
如果onfulfilled不是一个函数,promise2以promise1的value触发fulfilled
如果onrejected不是一个函数,promise2以promise1的reason触发rejected
7 resolvePromise(promise2, x, resolve, reject)
如果promise2和x相等,那么reject typeError
如果x是一个promise
如果x是Pending,promise一定继续pending,直到x变成fulfilled 或者 rejected
如果x是fulfilled,resolve same value
如果x是rejected,reject same value
如果x是Object或者function
try
let then=x.then;
catch(e)
reject promise
如果x.then是一个函数,then.call(x,resolvePromiseFn,rejectPromiseFn) 改变this指向
如果then不是一个函数,fulfilled promise x
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
class PromiseM {
FULFILLED_CALLBACK_LIST = [];
REJECTED_CALLBACK_LIST = [];
_status = PENDING;
constructor(fn) {
this.status = PENDING;
this.value = null;
this.reason = null;
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e)
}
}
get status() {
return this._status
}
set status(newStatus) {
this._status = newStatus;
switch (newStatus) {
case FULFILLED: {
this.FULFILLED_CALLBACK_LIST.forEach(callback => {
callback(this.value)
})
break;
}
case REJECTED: {
this.REJECTED_CALLBACK_LIST.forEach(callback => {
callback(this.reason)
})
break;
}
}
}
resolve(value) {
if (this.status === PENDING) {
this.value = value
this.status = FULFILLED;
}
}
reject(reason) {
if (this.status === PENDING) {
this.reason = reason
this.status = REJECTED;
}
}
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value
};
const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
const promise2 = new PromiseM((resolve, reject) => {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
const rejectedMicrotast = () => {
queueMicrotask(() => {
try {
const x = realOnRejected(this.reason)
this.resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
switch (this.status) {
case FULFILLED: {
fulfilledMicrotask();
break;
}
case REJECTED: {
rejectedMicrotast()
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotast)
}
}
})
return promise2;
}
catch(onRejected) {
return this.then(null, onRejected)
}
isFunction(param) {
return typeof param === 'function';
}
resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(new TypeError('The promise and the return value are the same'))
}
if (x instanceof PromiseM) {
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject)
}, reject);
})
} else if (typeof x === 'object' || this.isFunction(x)) {
if (x === null) {
return resolve(x);
}
let then = null;
try {
then = x.then
} catch (e) {
return reject(e)
}
if (this.isFunction(then)) {
let called = false;
try {
then.call(x,
(y) => {
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return;
called = true;
reject(r)
})
} catch (e) {
if (called) return;
reject(e)
}
} else {
resolve(x)
}
} else {
resolve(x);
}
}
static resolve(value) {
if (value instanceof PromiseM) {
return value
}
return new PromiseM((resolve) => {
resolve(value)
})
}
static reject(reason) {
return new PromiseM((resolve, reject) => {
reject(reason)
})
}
static race(promiseList) {
return new PromiseM((resolve, reject) => {
const length = promiseList;
if (length === 0) {
return resolve()
} else {
for (let i = 0; i < length; i++) {
PromiseM.resolve(promiseList[i]).then(
(value) => {
return resolve(value)
},
(reason) => {
return reject(reason)
}
)
}
}
})
}
static resolved(value) {
var d = new Deferred();
d.resolve(value);
return d.promise;
}
static rejected(value) {
var d = new Deferred();
d.reject(value);
return d.promise;
}
}
function Deferred() {
this.promise = new PromiseM(function (resolve, reject) {
this._resolve = resolve;
this._reject = reject;
}.bind(this));
}
Deferred.prototype.resolve = function (value) {
this._resolve.call(this.promise, value)
}
Deferred.prototype.reject = function (reason) {
this._reject.call(this.promise, reason)
}
var dummy = {
dummy: "dummy"
}
var sentinel = {
sentinel: "sentinel"
}
var other = {
other: "other"
}
function xFactory() {
var d = new Deferred();
setTimeout(function () {
d.resolve(sentinel);
}, 50);
return {
then: function (resolvePromise, rejectPromise) {
resolvePromise(d.promise);
rejectPromise(other);
}
}
}
var promise = PromiseM.resolved(dummy).then(function onBasePromiseFulfilled() {
return xFactory();
})
promise.then(res => {
console.log("success", res)
}, res => {
console.log("err", res)
})
const test = new PromiseM((resolve, reject) => {
setTimeout(() => {
reject(111)
}, 1000);
}).then((value) => {
console.log('then', value)
}).catch((reason) => {
console.log('catch')
})
function longTimeFn(time) {
return new Promise((resolve) => {
setTimeout(() => {
resolve(time);
}, time);
})
}
function* generator() {
const list = [1, 2, 3]
for (let i of list) {
yield i
}
}
let g = generator();
// console.log(g.next())
// console.log(g.next())
// console.log(g.next())
// console.log(g.next())
function asyncFunc(generator) {
const iterator = generator();
const next = data => {
const { value, done } = iterator.next(data);
if (done) { return };
value.then(data => {
next(data);
})
}
next();
}
asyncFunc(function* () {
let data = yield longTimeFn(1000);
console.log(data);
data = yield longTimeFn(2000);
console.log(data);
return data
})