13

Promise是一种异步编程的解决方案,相比传统回调函数更合理.

1.Promise立即执行性

let p = new Promise((resolve, reject) => {
    console.log('立即执行!');
    resolve('返回成功!')
});

console.log('promise后执行!');

p.then(value => {
    console.log(value)
});

控制台输出:

"立即执行!"
"promise后执行!"
"返回成功!"

Promise对象表示未来发生的事件,在创建promise时,作为promise参数传入的函数是会被立即执行的,只是其中执行的代码可以是异步代码.有些人会认为,当promise对象调用then方法时,promise接受的函数才会执行,这是错误的.所以,代码中立即执行!先于promise后执行!输出.

2.Promise的三种状态.

let p1 = new Promise((reslove, reject) => {
    reslove(1);
});
let p2 = new Promise((reslove, reject) => {
    setTimeout(() => {
        reslove(2);
    }, 500);
});
let p3 = new Promise((reslove, reject) => {
    setTimeout(() => {
        reject(3);
    }, 500);
});

console.log(p1);
console.log(p2);
console.log(p3);
setTimeout(() => {
    console.log(p2);
}, 1000);
setTimeout(() => {
    console.log(p3);
}, 1000);

p1.then(value => {
    console.log(value);
});
p2.then(value => {
    console.log(value);
});
p3.catch(err => {
    console.log(err);
});

控制台输出:

Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 1}
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
1
2
3
Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 2}
Promise {[[PromiseStatus]]: "rejected", [[PromiseValue]]: 3}

Promise内部实现是一个状态机.Promise有三种状态: pending,resolved,rejected.当Promise刚创建完成时,处于pending状态;当Promise中的函数参数执行了resolve后,Promise由pending状态变成resloved状态;如果Promise的函数参数中执行的是reject方法,那么Promise会有pending状态变成rejected状态.

3.Promise状态不可逆性.

let p1 = new Promise((reslove, reject) => {
    reslove('成功1!');
    reslove('成功2!');
});
let p2 = new Promise((reslove, reject) => {
    reslove('成功!');
    reject('失败!');
});

p1.then(value => {
    console.log(value);
});
p2.then(value => {
    console.log(value);
});

控制台输出:

"成功1!"
"成功!"

Promise的状态一旦变成resolved或rejected时,Promise的状态和值就固定下来了,无论后续再怎么调用reslove或是reject方法,都不能改变它的状态和值.所以,p1中reslove('成功2!')并不能将p1的值更改为成功2!,p2中reject('失败!')也不能将p2的状态由resolved改变为rejected.

4.链式调用.

let p = new Promise((resolve, reject) => {
    resolve(1);
});

p.then(value => {
    console.log(value);
    return value * 2;
}).then(value => {
    console.log(value);
}).then(value => {
    console.log(value);
    return Promise.resolve('resolve');
}).then(value => {
    console.log(value);
    return Promise.reject('reject');
}).then(value => {
    console.log(`resolve: ${value}`);
}, err => {
    console.log(`reject: ${err}`);
})

控制台输出:

1
2
undefined
"resolve"
"reject: reject"

Promise对象的then方法返回一个新的Promise对象,所以可以通过链式调用then方法.then方法接受两个函数作为参数,第一个参数是Promise执行成功时的回调,第二个参数是Promise执行失败时的回调.两个函数只会有一个被调用,函数返回值将用作创建then返回的Promise对象.这两个参数的返回值可以是下面三种情况的一种:

①:return一个同步的值,或者undefined(当没有返回一个有效值时,默认返回undefined),then方法将返回一个resloved状态的Promise对象,Promise对象的值就是这个返回值.
②:return另一个Promise,then方法将根据这个Promise的状态和值创建一个新的Promise对象返回.
③:throw一个同步异常,then方法将返回一个rejected状态的Promise,值是该异常.

根据以上分析,代码中的第一个then会返回一个值为2(1 * 2),状态为resolved的Promise对象,于第二个then输出的值为2.第二个then中没有返回值,因此将返回默认的undefined,于是在第三个then中输出的undefined.第三个then和第四个then中分别返回一个状态是resloved的Promise和一个状态是rejected的Promise,依次由第四个then中的成功回调函数和第五个then中的失败回调函数处理.
5.Promise then()回调异步性.

let p = new Promise((resolve, reject) => {
    resolve('成功!');
});

p.then(value => {
    console.log(value);
});

console.log("谁先执行?")

控制台输出:

"谁先执行?"
"成功!"

Promise接受的函数参数是同步执行的,但是then方法中的回调函数则是异步的,因此,成功!会在后面输出.
6.Promise中的异常.

let p1 = new Promise((resolve, reject) => {
    foo.bar();
    resolve(1);
});

p1.then(value => {
    console.log(`p1 then value: ${value}`);
}, err => {
    console.log(`p1 then err: ${err}`);
}).then(value => {
    console.log(`p1 then then value: ${value}`);
}, err => {
    console.log(`p1 then then err: ${err}`);
});

let p2 = new Promise((resolve, reject) => {
    resolve(2);
});

p2.then(value => {
    console.log(`p2 then value: ${value}`);
    foo.bar();
}, err => {
    console.log(`p2 then err: ${err}`);
}).then(value => {
    console.log(`p2 then then value: ${value}`);
}, err => {
    console.log(`p2 then then err: ${err}`);
    return 1;
}).then(value => {
    console.log(`p2 then then then value: ${value}`);
}, err => {
    console.log(`p2 then then then err: ${err}`);
});

控制台输出:

p1 then err: ReferenceError: foo is not defined
p2 then value: 2
p1 then then value: undefined
p2 then then err: ReferenceError: foo is not defined
p2 then then then value: 1

Promise中的异常由then参数中的第二个回调函数(Promise执行失败的回调)处理,异常信息将作为Promise的值.异常一旦得到处理,then返回后续的Promise对象将恢复正常,并会被Promise执行成功的回调函数处理.另外,需要注意p1,p2多级then的回调函数是交替执行的,这正是由Promise then回调的异步性决定的.

7.Promise.reslove().

let p1 = Promise.resolve(1);
let p2 = Promise.resolve(p1);
let p3 = new Promise((resolve, reject) => {
    resolve(1);
});
let p4 = new Promise((resolve, reject) => {
    resolve(p1);
});

console.log(p1 === p2);
console.log(p1 === p3);
console.log(p1 === p4);
console.log(p3 === p4);

p4.then(value => {
    console.log(`p4=${value}`)
});
p2.then(value => {
    console.log(`p2=${value}`)
});
p1.then(value => {
    console.log(`p1=${value}`)
});

控制台输出:

true
false
false
false
p2=1
p1=1
p4=1

Promise.resolve(...) 可以接受一个值或者是一个Promise对象作为参数.当参数是普通值时,它返回一个resolved状态的Promise对象,对象的值就是这个参数;当参数是一个Promise对象时,它直接返回这个Promise参数.所以p1===p2.但通过new创建的Promise对象都是一个新的对象,所以后面三个比较结果都是false.另外,为什么p4的then最先调用,但是在控制台上是最后输出结果的呢?因为p4中resolve接受的参数是一个Promise对象p1,reslove会对p1进行解析,获取p1的状态和值,但是这个过程是异步的.

8.resolve v reject.

let p1 = new Promise((resolve, reject) => {
    resolve(Promise.resolve('resolve'));
});
let p2 = new Promise((resolve, reject) => {
    resolve(Promise.reject('reject'));
});
let p3 = new Promise((resolve, reject) => {
    reject(Promise.resolve('resolve'));
});

p1.then(value => {
    console.log(`p1 fulfilled: ${value}`);
}, err => {
    console.log(`p1 rejected: ${err}`);
});
p2.then(value => {
    console.log(`p2 fulfilled: ${value}`);
}, err => {
    console.log(`p2 rejected: ${err}`);
});
p3.then(value => {
    console.log(`p3 fulfilled: ${value}`);
}, err => {
    console.log(`p3 rejected: ${err}`);
});

控制台输出:

p3 rejected: [object Promise]
p1 fulfilled: resolve
p2 rejected: reject

Promise回调函数中的第一个参数resolve,会对Promise执行解析,即resolve的参数是Promise对象时,resolve会解析获取这个Promise对象的状态和值,但这个过程是异步的.p1解析后,获取到Promise对象的状态是resolved,因此第一个回调被执行也就是获取value的回调;p2解析后,获取到Promise对象的状态rejected,因此rejected回调执行.但Promise回调函数中的第二个参数reject不具备解析能力,reject的参数会直接传递给then方法中的rejected回调,因此,即使p3 reject接受了一个resolved状态的Promise,then方法中调用的依然是rejected,并且参数就是reject接受到的Promise对象.


伍陆柒
1.2k 声望25 粉丝

如果觉得我的文章对大家有用的话, 可以去我的github start一下[链接]