promise
Promise的使用方法
一.定义:
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。它由社区最早提出和实现,ES6 将其写进了语言标准,统一了用法,原生提供了Promise
对象。
二.特点:
(1)对象的状态不受外界影响。Promise
对象代表一个异步操作,有三种状态:pending
(进行中)、fulfilled
(已成功)和rejected
(已失败)。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。Promise
对象的状态改变,只有两种可能:从pending
变为fulfilled
和从pending
变为rejected
。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型)。-------------------------------也就是说当执行了包含promise对象的回调时,结果只可能是执行成功或执行失败,且不可能从成功的状态变为失败的状态或从失败的状态变为成功的状态。最典型的例子是Ajax和axios请求后端接口。
三.用法:
(1)Promise对象是一个构造函数,所以创建Promise时也要同Array,Object一样使用new命令,Promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。
<script> function fn(flag) { //构造函数 return new Promise(function(resolve, reject) { if (flag === true) { resolve('promise状态为成功!') }; if (flag === false) { reject('promise状态失败!') }; }) } console.log(fn(true)); //promise状态为成功!
</script>
(2)Promise
实例生成以后,可以用then
方法分别指定resolved
状态和rejected
状态的回调函数。
function fn(flag) { let judge = new Promise(function(resolve, reject) { if (flag === true) { resolve('promise状态为成功!') }; if (flag === false) { reject('promise状态失败!') }; });
//judge是一个promise实例
judge.then(function(res) { console.log(res); },
function(err) { console.log(err); })
} fn(true) //promise状态为成功!
fn(false) //promise状态失败!
(3)promise的异步结果,只能在完成状态时才能返回,而且我们在开发中是根据结果来选择状态的,然后根据状态来选择是否执行then()。实例化的Promise内部会立即执行,then方法中的异步回调函数会在脚本中所有同步任务完成时才会执行。因此,promise的异步回调结果最后输出。示例代码如下:
<script> let promise = new Promise(function(resolve, reject) { console.log('Promise'); resolve(); }); promise.then(function() { console.log('resolved.'); }); console.log('Hi!'); </script>
四.如果我们既要使用异步(使用异步会优先运行非异步的代码),又要使用异步函数改变的或者是获取的参数就会导致意想不到的错误。
function getData () { var data; let promise = new Promise(function (resolve, reject) { resolve(); }).then(function () { data={name:'小明'} console.log(1111,data.name); }); console.log(2222, data.name) return promise } getData()
(1)可以看到使用了promise.then的异步方法后,getData()函数首先执行的是console.log(2222,data.name),而promise还未执行。由于此时的data类型和name属性都未定义,便抛出了错误,然后再执行promise.then中的代码,最后正确答应console.log(1111,data.name);
(2)现在我们需要的方法是,先执行promise的异步操作后再执行后面的代码怎么办呢?--------------------为解决这一难题我们就需要后面的代码去“等待”--->await
通常 await和async是同时使用的,await只能出现再async的内部,详见https://es6.ruanyifeng.com/#docs/async。
async function getData () { var data; let promise = await new Promise(function (resolve, reject) { resolve(); }).then(function () { data={name:'小明'} console.log(1111,data.name); }); console.log(2222, data.name) return promise } getData()
如上代码所示,我们在getData函数前面加了async,在promise前面加了await;代码的执行顺序就是依次执行;
可以理解为: 当执行到await时,代码异步执行,当执行完毕后,再执行其后的代码。
Promise.all
Promise.all()
方法用于将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.all([p1, p2, p3]);
上面代码中,Promise.all()方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例,如果不是,就会先调用 Promise.resolve方法,将参数转为 Promise 实例,再进一步处理。另外,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。
p的状态由 p1、p2、p3决定,分成两种情况。
(1)只有 p1、p2、p3的状态都变成 fulfilled,p的状态才会变成 fulfilled,
此时p1、p2、p3的返回值组成一个数组,传递给 p的回调函数。
(2)只要 p1、p2、p3之中有一个被 rejected,p的状态就变成 rejected,
此时第一个被 reject的实例的返回值,会传递给 p的回调函数。