共计 6989 个字符,预计需要花费 18 分钟才能阅读完成。
一、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 的值是 undefined
Promise.resolve(2).then(() => {}, () => {})
// resolve 的值是 2
Promise.resolve(2).finally(() => {})
// reject 的值是 undefined
Promise.reject(3).then(() => {}, () => {})
// reject 的值是 3
Promise.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')