一、promise
1、介绍
Promise 是异步编程的一种解决方案,比传统的解决方案“回调函数和事件”,更正当和更弱小。
异步操作的长处:
- 链式操作减低了编码难度(解决回调天堂问题)
- 代码可读性明显增强
状态
promise对象仅有三种状态
pending(进行中)
fulfilled(已胜利)
rejected(已失败)
特点:
(1)对象的状态不受外界影响。只有异步操作的后果,能够决定以后是哪一种状态。
(2)一旦状态扭转,就不会再变,任何时候都能够失去这个后果(从pending
变为fulfilled
和从pending
变为rejected
)。
2、根本用法
Promise对象是一个构造函数,用来生成Promise实例
const promise = new Promise(function(resolve, reject) {});
Promise构造函数承受一个函数作为参数,该函数的两个参数别离是resolve和reject
resolve
函数的作用是,将Promise对象的状态从“未实现”变为“胜利”reject
函数的作用是,将Promise对象的状态从“未实现”变为“失败”
Promise实例生成当前,能够用then办法别离指定resolved状态和rejected状态的回调函数。
// 第一个回调在resolve时调用,第二个回调在rejected时调用promise.then(function(value) { // success}, function(error) { // failure});promise.then(function(value) { // success}).catch(function(value) { // failure});
Promise 新建后就会立刻执行,能够来看个例子:
let promise = new Promise(function(resolve, reject) { console.log('Promise'); resolve();});promise.then(function() { console.log('resolved.');});console.log('Hi!');// Promise// Hi!// resolved.
promise新建之后立刻执行,因而打印了Promise,then办法的回调函数是在以后脚本所有同步工作执行完才会执行,因而resolved.最初输入。
3、实例办法
Promise构建进去的实例存在以下办法:
then()
catch()
finally()
then()
then是实例状态产生扭转时的回调函数,第一个参数在resolve时调用,第二个参数在rejected时调用
then办法返回新的promise实例,能够进行链式写法。
getJSON("/posts.json").then(function(json) { return json.post;}).then(function(post) { // ...}, function (err){ console.log("rejected: ", err);});
catch()
catch()办法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定产生谬误时的回调函数
const promise = new Promise(function(resolve, reject) { throw new Error('test');});promise.catch(function(error) { console.log(error);});// Error: test//下面代码中,promise抛出一个谬误,就被catch()办法指定的回调函数捕捉。留神,下面的写法与上面两种写法是等价的。// 写法一const promise = new Promise(function(resolve, reject) { try { throw new Error('test'); } catch(e) { reject(e); }});promise.catch(function(error) { console.log(error);});// 写法二const promise = new Promise(function(resolve, reject) { reject(new Error('test'));});promise.catch(function(error) { console.log(error);});比拟下面两种写法,能够发现reject()办法的作用,等同于抛出谬误
注意事项:
(1)try...catch 不能捕捉有效js代码
try { ===} catch(err) { // 不会执行 console.log(err)}
(2)try...catch 不能捕捉异步代码
try { setTimeout(() => {console.log(1)}, 1000)} catch(err) { console.log(err)}
getJSON('/posts.json').then(function(posts) { // ...}).catch(function(error) { // 解决 getJSON 和 前一个回调函数运行时产生的谬误 console.log('产生谬误!', error);});
Promise 对象的谬误具备“冒泡”性质,会始终向后传递,直到被捕捉为止
getJSON('/post/1.json').then(function(post) { return getJSON(post.commentURL);}).then(function(comments) { // some code}).catch(function(error) { // 解决后面三个Promise产生的谬误});
一般来说,应用catch办法代替then()第二个参数
Promise 对象抛出的谬误不会传递到外层代码,即不会有任何反馈
const someAsyncThing = function() { return new Promise(function(resolve, reject) { // 上面一行会报错,因为x没有申明 resolve(x + 2); });};
浏览器运行到这一行,会打印出谬误提醒ReferenceError: x is not defined,然而不会退出过程
catch()办法之中,还能再抛出谬误,通过前面catch办法捕捉到(再写一个catch办法捕捉异样)。
const someAsyncThing = function() { return new Promise(function(resolve, reject) { // 上面一行会报错,因为x没有申明 resolve(x + 2); });};someAsyncThing().then(function() { return someOtherAsyncThing();}).catch(function(error) { console.log('oh no', error); // 上面一行会报错,因为 y 没有申明 y + 2;}).then(function() { console.log('carry on');});// oh no [ReferenceError: x is not defined]
finily()
finally()办法用于指定不论 Promise 对象最初状态如何,都会执行的操作
promise.then(result => {···}).catch(error => {···}).finally(() => {···});
finally办法总是会返回原来的值。
// resolve 的值是 undefinedPromise.resolve(2).then(() => {}, () => {})// resolve 的值是 2Promise.resolve(2).finally(() => {})// reject 的值是 undefinedPromise.reject(3).then(() => {}, () => {})// reject 的值是 3Promise.reject(3).finally(() => {})
4、构造函数
Promise构造函数存在以下办法:
all()
race()
allSettled()
resolve()
reject()
try()
all()
all()办法用于将多个 Promise 实例,包装成一个新的 Promise 实例
const p = Promise.all([p1, p2, p3]);
p的状态由p1、p2、p3决定,分成两种状况。
(1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、p2、p3的返回值组成一个数组,传递给p的回调函数。
(2)只有p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值,会传递给p的回调函数。
作为参数的promise实例定义了catch办法,产生rejected时不会触发promise.call的catch办法。如果没有定义catch办法,则就会调用Promise.all()的catch办法。
const p1 = new Promise((resolve, reject) => { resolve('hello');}).then(result => result).catch(e => e);const p2 = new Promise((resolve, reject) => { throw new Error('报错了');}).then(result => result).catch(e => e);Promise.all([p1, p2]).then(result => console.log(result)).catch(e => console.log(e));// ["hello", Error: 报错了]
5、应用场景
(1)将图片的加载写成一个Promise,一旦加载实现,Promise的状态就发生变化
const preloadImage = function (path) { return new Promise(function (resolve, reject) { const image = new Image(); image.onload = resolve; image.onerror = reject; image.src = path; });};
(2)当下个异步申请依赖上个申请后果的时候,咱们也可能通过链式操作敌对解决问题
(3)实现多个申请合并在一起,汇总所有申请后果
二、async
1、介绍
async函数的返回值是 Promise 对象
进一步说,async函数齐全能够看作多个异步操作,包装成的一个 Promise 对象,而await命令就是外部then命令的语法糖。
2、语法
async function name([param[, param[, ... param]]]) { statements }
name
: 函数名称。param
:要传递给函数的参数的名称。statements
: 函数体语句。
async前面跟着函数,不能跟着其它字符(如数字、字符串等)
3、根本用法
async 函数返回一个 Promise 对象,能够应用 then 办法增加回调函数。
async function helloAsync(){ return "helloAsync"; } console.log(helloAsync()) // Promise {<resolved>: "helloAsync"} helloAsync().then(v=>{ console.log(v); // helloAsync})
async 函数中可能会有 await 表达式,async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作实现后,复原 async 函数的执行并返回解析值。
await 关键字仅在 async function 中无效。如果在 async function 函数体外应用 await ,你只会失去一个语法错误。
function testAwait(){ return new Promise((resolve) => { setTimeout(function(){ console.log("testAwait"); resolve(); }, 1000); });}// 等同于async function testAwait(){ await new Promise((resolve) => { setTimeout(function(){ console.log("testAwait"); resolve(); }, 1000); });} async function helloAsync(){ await testAwait(); console.log("helloAsync"); }helloAsync();// testAwait// helloAsync
async函数会返回一个promise,状态值是resolved
1、在async函数中写return,那么Promise对象resolve的值就是是undefined
2、rerun的值作为resolved的值
三、await
1、介绍
await
前面接一个会return new promise的函数并执行它await
只能放在async函数里
2、语法
[return_value] = await expression;
expression: 一个 Promise 对象或者任何要期待的值。
3、根本用法
await命令前面是一个 Promise 对象,返回该对象的后果。如果不是 Promise 对象,就间接返回对应的值
async function f() { // 等同于 // return 123; return await 123;}f().then(v => console.log(v))// 123
await 命令前面是一个 Promise 对象,它也能够跟其余值,如字符串,布尔值,数值以及一般函数。
function testAwait(){ console.log("testAwait");}async function helloAsync(){ await testAwait(); console.log("helloAsync");}helloAsync();// testAwait// helloAsync
await针对所跟不同表达式的解决形式:
Promise 对象:await 会暂停执行,期待 Promise 对象 resolve,而后复原 async 函数的执行并返回解析值。
非 Promise 对象:间接返回对应的值。
任何一个await语句前面的 Promise 对象变为reject状态,那么整个async函数都会中断执行。
async function f() { await Promise.reject('出错了'); await Promise.resolve('hello world'); // 不会执行}f().then().catch() // catch捕捉异样
想要前一个异步操作失败,也不要中断前面的异步操作
1、应用try..catch
2、await前面的 Promise 对象再跟一个catch办法,解决后面可能呈现的谬误。
4、留神点
1、多个await命令前面的异步操作,如果不存在继发关系,最好让它们同时触发。
let foo = await getFoo();let bar = await getBar();// 写法一let [foo, bar] = await Promise.all([getFoo(), getBar()]);// 写法二let fooPromise = getFoo();let barPromise = getBar();let foo = await fooPromise;let bar = await barPromise;
2、await命令只能用在async函数之中,如果用在一般函数,就会报错
// 报错async function hh() { setTimeout(() => {await b()},1000)}// 正确写法function hh() { setTimeout(async () => {await b()},1000) // await紧跟着async}
四、思考题
console.log('script start')async function async1() { console.log('async1 start') await async2() console.log('async1 end') return 'async then'}async function async2() { console.log('async2 end')}async1()setTimeout(function() { console.log('setTimeout')}, 0)async1().then(function (message) { console.log(message) })new Promise(resolve => { console.log('Promise') resolve()}) .then(function() { console.log('promise1') }) .then(function() { console.log('promise2') })console.log('script end')