您的位置:首页 > Web前端 > JavaScript

从零开始学_JavaScript_系列(48)——Promise(1)基础知识

2017-07-28 10:04 501 查看

1、是什么

一个十分适合处理异步操作的对象

有进行中(pending)、成功(resolved)、失败(rejected)三种状态

可以轻松处理成功或失败的情况,代码结构更清爽,操作结果可预期

对象的状态不受外界影响,只会根据预先设定的情况执行代码,方便从pending状态切换到resolved或者rejected

Promise对象在创建后会立即执行,但他的then是异步的(即使状态立刻改变,也要等其他代码执行完毕后才会去执行)

Promise对象的状态改变是一次性的,改变后值即确定。不会因为任何情况导致状态反复变化

Promise的状态改变后,会立刻触发其回调函数(执行resolve或者reject)

Promise对象foo可以作为另外一个Promise对象bar的值,并且在foo和bar的状态都不是pending后,才会执行bar的回调

Promise对象的then的值是Promise对象,但和最初的Promise不是同一个

then可以连写,方便连续异步函数的调用

Promise.all可以轻松处理多个异步操作,在全部完成后才应执行的逻辑

Promise.race可以轻松处理多个异步操作,但只需要最快的那个异步操作结果的情况

Promise.resolve和Promise.reject可以轻松将一个变量转为Promise对象并使用

2、基本例子

Promise有几个特点:

new出来后立刻执行;

只执行一次,并且结果发生后,无论之后几次调用then,都只执行那唯一一个结果(resolve或者reject);

如果处于pending中,那么执行then时,相当于添加到队列里,pending中不执行,但等结果出来后,会一起执行(而非只执行一个或者不执行);

resolve或者reject只能接受一个参数,如果要传多个参数的话,请使用数组或者对象的形式;

resolve和reject里函数不是在声明时执行,而是异步的,在判定promise的状态为非pending状态时执行;

如以下示例:

console.log(new Date);
let foo = new Promise(function (resolve, reject) {
setTimeout(function () {
//获取毫秒的数值
var d = (new Date()).getMilliseconds();
if (d % 2 === 0) {
resolve([new Date(), d]);
} else {
reject([new Date(), d]);
}
}, 1000);
})

foo.then(function (arr) {
console.log(new Date);
console.log("resolve: " + arr[0]);
}, function (arr) {
console.log("reject: " + arr[0]);
})

foo.then(function (arr) {
console.log(arr[1]);
console.log("resolve: " + arr[0]);
}, function (arr) {
console.log(arr[1]);
console.log("reject: " + arr[0]);
})

//Tue Jul 04 2017 00:06:52 GMT+0800 (中国标准时间)

/* 然后,1秒后 */
//reject: Tue Jul 04 2017 00:06:53 GMT+0800 (中国标准时间)
//633
//reject: Tue Jul 04 2017 00:06:53 GMT+0800 (中国标准时间)


以上代码证明了第2,3,4点。而第一点和第五点通过以下代码证明:

let foo = new Promise(function (resolve, reject) {
resolve();
console.log("in Promise");
})

console.log("after Promise");

foo.then(function (arr) {
console.log("in resolve");
});

console.log("at last");

//in Promise
//after Promise
//at last
//in resolve


证明除了resolve和reject中的代码是异步的之外,其他都是顺序执行(位于foo.then后的代码先执行,之后才执行了foo.then的回调函数)。

3、当两个Promise对象发生交互时

具体来说,Promise实例在执行回调函数时可以传一个参数,而这个参数可以是另外一个Promise实例的回调函数。如代码:

let foo = new Promise(function (res, rej) {
setTimeout(function () {
res("1")
}, 1000)
})
let bar = new Promise(function (res, rej) {
res(foo);    //参数是foo实例
})


在这种情况下,bar的回调函数并不会立即执行,而是会等待foo的状态改变后,再去执行bar的回调函数。

即当Promise实例bar的回调函数的参数是另外一个Promise实例foo时,bar在状态改变后不会立即执行,而是等待前一个Promise实例的状态发生改变后,他才会执行。

情况foobar
基本情况一个Promise实例bar的then的回调函数的参数是foo
延迟等待时间:foo小于bar先执行后执行
延迟等待时间:foo大于bar先执行等待foo执行完后即执行
如代码:

let foo = new Promise(function (res, rej) {
setTimeout(function () {
res("1")
}, 1500)
})
let bar = new Promise(function (res, rej) {
setTimeout(function () {
console.log(bar);
}, 1000)
setTimeout(function () {
res(foo);
}, 500)
})
let baz = new Promise(function (res, rej) {
res("3");
})

foo.then(function (val) {
console.log("foo: " + val);
})
bar.then(function (val) {
console.log("bar: " + val);
})
baz.then(function (val) {
console.log("baz: " + val);
})

//bar: 3
//状态为"pending"
//foo: 1
//bar: 1


如上代码:

bar因为没有延迟,也没有依赖,所以先执行了;

bar虽然500ms后就可以执行,但因为依赖于bar,所以在等待foo执行,注意,此时其状态依然为pending,而不是resolved;

foo在1500ms后执行完毕;

bar发现foo执行完毕了,自己也可以执行,所以跟着执行了;

除此之外,还有几个特点:

作为参数的Promise实例,他会将自己的参数的值传递给另一个Promise实例,即bar的resolve的参数是foo,而foo的resolve的参数的值是”1”,因此bar的resolve的参数的值是”1”;

两个Promise实例要执行的必须都是resolve或者都是reject,不然不会互相影响;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: