Promise/A+规范
Promise/A+规范原文: promisesaplus.com/
Promise/A+规范译文: www.ituring.com.cn/article/665…
1. Promise
基本结构
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('FULFILLED')
}, 1000)
})
构造函数
Promise
必须接受一个函数作为参数,我们称该函数为handle
,handle
又包含resolve
和reject
两个参数,它们是两个函数。
定义一个判断一个变量是否为函数的方法,后面会用到
// 判断变量否为function
isFunction(param) {
return typeof param === 'function';
}
首先,我们定义一个名为 MyPromise
的 Class
,它接受一个函数 handle
作为参数
class MPromise {
constructor(fn) {
// Do Something
}
isFunction(param) {
return typeof param === 'function';
}
}
再往下看
2. Promise
状态和值
Promise
对象存在以下三种状态:
Pending(进行中)
Fulfilled(已成功)
Rejected(已失败)
状态只能由
Pending
变为Fulfilled
或由Pending
变为Rejected
,且状态改变之后不会在发生变化,会一直保持这个状态。
Promise
的值是指状态改变时传递给回调函数的值
上文中
handle
函数包含resolve
和reject
两个参数,它们是两个函数,可以用于改变Promise
的状态和传入Promise
的值
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('FULFILLED')
}, 1000)
})
这里 resolve
传入的 "FULFILLED"
就是 Promise
的值
resolve` 和 `reject
resolve
: 将Promise对象的状态从Pending(进行中)
变为Fulfilled(已成功)
reject
: 将Promise对象的状态从Pending(进行中)
变为Rejected(已失败)
resolve
和reject
都可以传入任意类型的值作为实参,表示Promise
对象成功(Fulfilled)
和失败(Rejected)
的值
了解了 Promise
的状态和值,接下来,我们为 MyPromise
添加状态属性和值
首先定义三个常量,用于标记Promise对象的三种状态
// 定义Promise的三种状态常量
const PENDING = 'pending'; // 进行中
const FULFILLED = 'fulfilled'; // 已成功
const REJECTED = 'rejected'; // 已失败
再为
MyPromise
添加状态和值,并添加状态改变的执行逻辑
// 定义Promise的三种状态常量
const PENDING = 'pending'; // 进行中
const FULFILLED = 'fulfilled'; // 已成功
const REJECTED = 'rejected'; // 已失败
class MPromise {
// Promise 对象状态
_status = PENDING;
constructor(fn) {
// 初始状态为pending
this.status = PENDING;
this.value = null;
this.reason = null;
// 执行回调
try {
fn(this.resolve.bind(this), this.reject.bind(this));
} catch (e) {
this.reject(e);
}
}
// 添加resovle时执行的函数
resolve(value) {
if (this.status === PENDING) {
this.value = value;
this.status = FULFILLED;
}
}
// 添加reject时执行的函数
reject(reason) {
if (this.status === PENDING) {
this.reason = reason;
this.status = REJECTED;
}
}
isFunction(param) {
return typeof param === 'function';
}
}
这样就实现了 Promise
状态和值的改变。下面说一说 Promise
的核心: then
方法
3. Promise
的 then
方法
Promise
对象的 then
方法接受两个参数:
promise.then(onFulfilled, onRejected)
参数可选
onFulfilled
和 onRejected
都是可选参数。
- 如果
onFulfilled
或onRejected
不是函数,其必须被忽略
onFulfilled 特性
如果 onFulfilled
是函数:
- 当
promise
状态变为成功时必须被调用,其第一个参数为promise
成功状态传入的值(resolve
执行时传入的值) - 在
promise
状态改变前其不可被调用 - 其调用次数不可超过一次
onRejected 特性
如果 onRejected
是函数:
- 当
promise
状态变为失败时必须被调用,其第一个参数为promise
失败状态传入的值(reject
执行时传入的值) - 在
promise
状态改变前其不可被调用 - 其调用次数不可超过一次
根据上面的规则,我们来为 完善 MyPromise
then(onFulfilled, onRejected) {
// 检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者reason.
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
// 其调用次数不可超过一次
switch (this.status) {
case FULFILLED: {
fulFilledFn(this.value);
break;
}
case REJECTED: {
rejectedFn(this.reason);
break;
}
}
}
这样写, 是在then函数被调用的瞬间就会执行. 那这时候如果status还没变成fulfilled或者rejected怎么办, 很有可能还是pending的。
那么我们首先要拿到所有的回调, 然后才能在某个时机去执行他.。新建两个数组, 来分别存储成功和失败的回调, 调用then的时候, 如果还是pending就存入数组。
修改 MPromise: 增加执行队列
// 定义Promise的三种状态常量
const PENDING = 'pending'; // 进行中
const FULFILLED = 'fulfilled'; // 已成功
const REJECTED = 'rejected'; // 已失败
class MPromise {
// 添加成功回调函数队列
FULFILLED_CALLBACK_LIST = [];
// 添加失败回调函数队列
REJECTED_CALLBACK_LIST = [];
// Promise 对象状态
_status = PENDING;
// .... 省略
}
由于 then
方法支持多次调用
let p = new Promise(function(){
resolve('我是成功');
})
p.then((data) => {console.log(data);},(err) => {});
p.then((data) => {console.log(data);},(err) => {});
p.then((data) => {console.log(data);},(err) => {});
// 输出结果
我是成功
我是成功
我是成功
为了实现这样的效果,则上一次的代码将要重新写过,我们可以把每次调用resolve的结果存入一个数组中,每次调用reject的结果存入一个数组。这就是为何会在上面定义两个数组,且分别在resolve()和reject()遍历两个数组的原因。因此,在调用resolve()或者reject()之前,我们在pending状态时,会把多次then中的结果存入数组中,则上面的代码会改变为:
在调用
resolve
和reject
方法时,需要将队列中存放的回调按照先后顺序依次调用(是不是感觉很像浏览器的事件环机制)。
then(onFulfilled, onRejected) {
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
switch (this.status) {
case FULFILLED: {
fulFilledFn(this.value);
break;
}
case REJECTED: {
rejectedFn(this.reason);
break;
}
// 我们可以维护两个数组,将每次 then 方法注册时的回调函数添加到数组中,等待执行
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(realOnFulfilled);
this.REJECTED_CALLBACK_LIST.push(realOnRejected);
break;
}
}
}
在status发生变化的时候, 就执行所有的回调。这里咱们用一下es6的getter和setter.。这样更符合语义, 当status改变时, 去做什么事情.。(当然也可以顺序执行, 在给status赋值后, 下面再加一行forEach)
get status() {
return this._status;
}
set 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;
}
}
}
多次调用
then
方法可以被同一个 promise
对象调用多次
- 当
promise
成功状态时,所有onFulfilled
需按照其注册顺序依次回调 - 当
promise
失败状态时,所有onRejected
需按照其注册顺序依次回调
返回
then
方法必须返回一个新的 promise
对象
promise2 = promise1.then(onFulfilled, onRejected);
因此 promise
支持链式调用
promise1.then(onFulfilled1, onRejected1).then(onFulfilled2, onRejected2);
检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者reason.
上面的方案,还顺带解决了值穿透的问题。所谓值穿透,就是调用 then 方法时,如果不传入参数,下层链条中的 then 方法还能够正常的获取到 value 或者 reason 值。
new MyPromise(resolve => setTimeout(() => { resolve("Success") }))
.then()
.then()
.then()
...
.then(data => console.log(data));
根据上面的规则,我们来为 完善 **MyPromise**
then(onFulfilled, onRejected) {
// 检查并处理参数, 之前提到的如果不是function, 就忽略. 这个忽略指的是原样返回value或者reason.
// 上面的方案,还顺带解决了值穿透的问题。所谓值穿透,就是调用 then 方法时,如果不传入参数,下层链条中的 then 方法还能够正常的获取到 value 或者 reason 值。
const fulFilledFn = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value;
}
const rejectedFn = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
// 规范还规定,then 方法必须返回一个新的 Promise 对象,以实现链式调用。
const promise2 = new MPromise((resolve, reject) => {
// 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
const fulfilledMicrotask = () => {
try {
const x = fulFilledFn(this.value);
resolve(x)
} catch (e) {
reject(e)
}
};
// 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因。
// 需要注意的是,如果promise1的onRejected执行成功了,promise2应该被resolve
const rejectedMicrotask = () => {
try {
const x = rejectedFn(this.reason);
resolve(x)
} catch (e) {
reject(e);
}
}
switch (this.status) {
case FULFILLED: {
fulfilledMicrotask()
break;
}
case REJECTED: {
rejectedMicrotask()
break;
}
// 在当前的 Promise 对象(promise1)的状态为 pending 时,将改变 promise2 状态的方法加入到回调函数的队列中。
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
}
}
})
return promise2
}
规范规定,then
方法必须返回一个新的 Promise 对象(promise2),新的 promise2 的状态必须依赖于调用 then
方法的 Promise 对象(promise1)的状态,也就是说,必须要等到 promise1 的状态变成 fulfilled
或者 rejected
之后,promise2 的状态才能进行改变。
因此,在 then
方法的实现中,在当前的 Promise 对象(promise1)的状态为 pending
时,将改变 promise2
状态的方法加入到回调函数的队列中。
值的传递
这里涉及到 Promise
的执行规则,包括“值的传递”和“错误捕获”机制:
1、如果 onFulfilled
或者 onRejected
返回一个值 x
,则运行下面的 Promise
解决过程:[[Resolve]](promise2, x)
- 若
x
不为Promise
,则使x
直接作为新返回的Promise
对象的值, 即新的onFulfilled
或者onRejected
函数的参数. - 若
x
为Promise
,这时后一个回调函数,就会等待该Promise
对象(即x
)的状态发生变化,才会被调用,并且新的Promise
状态和x
的状态相同。
下面的例子用于帮助理解:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
promise2 = promise1.then(res => {
// 返回一个普通值
return '这里返回一个普通值'
})
promise2.then(res => {
console.log(res) //1秒后打印出:这里返回一个普通值
})
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve()
}, 1000)
})
promise2 = promise1.then(res => {
// 返回一个Promise对象
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('这里返回一个Promise')
}, 2000)
})
})
promise2.then(res => {
console.log(res) //3秒后打印出:这里返回一个Promise
})
2、如果 onFulfilled
或者onRejected
抛出一个异常 e
,则 promise2
必须变为失败(Rejected)
,并返回失败的值 e
,例如:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
promise2 = promise1.then(res => {
throw new Error('这里抛出一个异常e')
})
promise2.then(res => {
console.log(res)
}, err => {
console.log(err) //1秒后打印出:这里抛出一个异常e
})
3、如果onFulfilled
不是函数且 promise1
状态为成功(Fulfilled)
, promise2
必须变为成功(Fulfilled)
并返回 promise1
成功的值,例如:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 1000)
})
promise2 = promise1.then('这里的onFulfilled本来是一个函数,但现在不是')
promise2.then(res => {
console.log(res) // 1秒后打印出:success
}, err => {
console.log(err)
})
4、如果 onRejected
不是函数且 promise1
状态为失败(Rejected)
,promise2
必须变为失败(Rejected)
并返回 promise1
失败的值,例如:
let promise1 = new Promise((resolve, reject) => {
setTimeout(() => {
reject('fail')
}, 1000)
})
promise2 = promise1.then(res => res, '这里的onRejected本来是一个函数,但现在不是')
promise2.then(res => {
console.log(res)
}, err => {
console.log(err) // 1秒后打印出:fail
})
根据上面的规则,我们来为 完善 **MyPromise**
,实现 resolvePromise 方法
上面的代码,处理了 onFulfilled
和 onRejected
方法的返回值的情况,以及实现了 then
方法的链式调用。
现在考虑一个问题,如果 onFulfilled
或 onRejected
方法返回的是一个 Promise 对象,或者是具有 then
方法的其他对象(thenable
对象),该怎么处理呢?
规范中提到,对于 onFulfilled
或 onRejected
的返回值的,提供一个 Promise Resolution Procedure 方法进行统一的处理,以适应不同的返回值类型。
我们将这个方法命名为 resolvePromise
方法,将其设计为 MyPromise 类上的一个静态方法。
resolvePromise
静态方法的作用,就是根据 onFulfilled
或 onRejected
不同的返回值(x
)的情况,来改变 then
方法返回的 Promise 对象的状态。
可以这样理解:我们将改变 promise2 对象的状态的过程,移动到了 resolvePromise
方法中,以便处理更多的细节问题。
下面是 resolvePromise
方法的实现:
resolvePromise(newPromise, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (newPromise === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (x instanceof MPromise) {
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
x.then((y) => {
resolvePromise(newPromise, y, resolve, reject);
}, reject);
} else if (typeof x === 'object' || this.isFunction(x)) {
// 如果 x 为对象或者函数
if (x === null) {
// null也会被判断为对象
return resolve(x);
}
let then = null;
try {
// then 方法可能设置了访问限制(setter),因此这里进行了错误捕获处理
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error);
}
// 如果 then 是函数
if (this.isFunction(then)) {
let called = false;
// 将 x 作为函数的作用域 this 调用
// 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
(y) => {
// 需要有一个变量called来保证只调用一次.
if (called) return;
called = true;
this.resolvePromise(promise, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
(r) => {
if (called) return;
called = true;
reject(r);
});
} catch (error) {
// 如果调用 then 方法抛出了异常 e:
if (called) return;
// 否则以 e 为据因拒绝 promise
reject(error);
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolve(x);
}
}
在实现规范的规程中,这个 resolvePromise
最最难理解的,主要是 return 链这里
if(x instanceof MyPromise){
// 处理返回值是 Promise 对象的情况
/**
* new MyPromise(resolve => {
* resolve("Success")
* }).then(data => {
* return new MyPromise(resolve => {
* resolve("Success2")
* })
* })
*/
x.then(y => {
// 用 x 的 fulfilled 后的 value 值 y,去设置 promise2 的状态
// 上面的注视,展示了返回 Promise 对象的情况,这里调用 then 方法的原因
// 就是通过参数 y 或者 reason,获取到 x 中的 value/reason
// 拿到 y 的值后,使用 y 的值来改变 promise2 的状态
// 依照上例,上面生成的 Promise 对象,其 value 应该是 Success2
// 这个 y 值,也有可能是新的 Promise,因此要递归的进行解析,例如下面这种情况
/**
* new Promise(resolve => {
* resolve("Success")
* }).then(data => {
* return new Promise(resolve => {
* resolve(new Promise(resolve => {
* resolve("Success3")
* }))
* })
* }).then(data => console.log(data))
*/
// 总之,使用 “return”链中最后一个 Promise 对象的状态,来决定 promise2 的状态
MyPromise.resolvePromise(promise2, y, resolve, reject)
},reason => {
reject(reason)
})
}
最后把then方法的传值方式修改为resolvePromise。
onFulfilled 和 onRejected 是微任务,可以用queueMicrotask包裹执行函数。
事件循环执行到微任务时,会把微任务放入微任务队列,待到执行栈代码执行完毕之后才会执行微软栈中的内容;因此使用了html的微任务api
queueMicrotask
将resolve和reject的回调函数放入微任务队列。
then(onFulfilled, onRejected) {
const realOnFulfilled = this.isFunction(onFulfilled) ? onFulfilled : (value) => {
return value
}
const realOnRejected = this.isFunction(onRejected) ? onRejected : (reason) => {
throw reason;
};
const promise2 = new MPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
// 使用了html的微任务apiqueueMicrotask将resolve和reject的回调函数放入微任务队列。
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
})
};
const rejectedMicrotask = () => {
// 使用了html的微任务apiqueueMicrotask将resolve和reject的回调函数放入微任务队列。
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: {
rejectedMicrotask()
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
}
}
})
return promise2
}
完整源码
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MPromise {
FULFILLED_CALLBACK_LIST = [];
REJECTED_CALLBACK_LIST = [];
_status = PENDING;
constructor(fn) {
// 初始状态为pending
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 MPromise((resolve, reject) => {
const fulfilledMicrotask = () => {
queueMicrotask(() => {
try {
const x = realOnFulfilled(this.value);
this.resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
})
};
const rejectedMicrotask = () => {
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: {
rejectedMicrotask()
break;
}
case PENDING: {
this.FULFILLED_CALLBACK_LIST.push(fulfilledMicrotask)
this.REJECTED_CALLBACK_LIST.push(rejectedMicrotask)
}
}
})
return promise2
}
catch (onRejected) {
return this.then(null, onRejected);
}
isFunction(param) {
return typeof param === 'function';
}
resolvePromise(promise2, x, resolve, reject) {
// 如果 newPromise 和 x 指向同一对象,以 TypeError 为据因拒绝执行 newPromise
// 这是为了防止死循环
if (promise2 === x) {
return reject(new TypeError('The promise and the return value are the same'));
}
if (x instanceof MPromise) {
// 如果 x 为 Promise ,则使 newPromise 接受 x 的状态
// 也就是继续执行x,如果执行的时候拿到一个y,还要继续解析y
queueMicrotask(() => {
x.then((y) => {
this.resolvePromise(promise2, y, resolve, reject);
}, reject);
})
} else if (typeof x === 'object' || this.isFunction(x)) {
// 如果 x 为对象或者函数
if (x === null) {
// null也会被判断为对象
return resolve(x);
}
let then = null;
try {
// 把 x.then 赋值给 then
then = x.then;
} catch (error) {
// 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise
return reject(error);
}
// 如果 then 是函数
if (this.isFunction(then)) {
let called = false;
// 将 x 作为函数的作用域 this 调用
// 传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调用,则运行 resolvePromise
(y) => {
// 需要有一个变量called来保证只调用一次.
if (called) return;
called = true;
this.resolvePromise(promise2, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promise
(r) => {
if (called) return;
called = true;
reject(r);
});
} catch (error) {
// 如果调用 then 方法抛出了异常 e:
if (called) return;
// 否则以 e 为据因拒绝 promise
reject(error);
}
} else {
// 如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
} else {
// 如果 x 不为对象或者函数,以 x 为参数执行 promise
resolve(x);
}
}
static resolve(value) {
if (value instanceof MPromise) {
return value;
}
return new MPromise((resolve) => {
resolve(value);
});
}
static reject(reason) {
return new MPromise((resolve, reject) => {
reject(reason);
});
}
static race(promiseList) {
return new MPromise((resolve, reject) => {
const length = promiseList.length;
if (length === 0) {
return resolve();
} else {
for (let i = 0; i < length; i++) {
MPromise.resolve(promiseList[i]).then(
(value) => {
return resolve(value);
},
(reason) => {
return reject(reason);
});
}
}
});
}
}
var m1 = new MPromise(function(resolve, reject){
resolve('resolve1');
}).then(console.log)
补充
针对resolve(promise)的情况下,.then底下onFulfilled和onRejected两个回调函数的入参获取情况,修改了一下路白老师的MPromise
resolve(value) {
if (this.status === PENDING) {
const promiseFinish = (promise,self) => {
promise.then(value=>{
self.value = value;self.status = FULFILLED;
},reason=>{
self.reason = reason;self.status = REJECTED;
})
}
value instanceof MPromise
? promiseFinish(value,this)
: (this.value = value,this.status = FULFILLED)
}
}
var m1 = new MPromise(function(resolve, reject){
resolve(MPromise.resolve('resolve1'));
});
m1.then(
function fulfilled(value){
console.log('fulfilled1: ' + value);
})
参考文章
作者:面条__
来源:掘金