promise可以接then操作,then操作可以接两个function参数,第一个function的参数就是构建Promise的时候resolve的value,第二个function的参数就是构建Promise的reject的error。
promise.then(function(value) { // success }, function(error) { // failure } );
我们看一个具体的例子:
function timeout(ms){ return new Promise(((resolve, reject) => { setTimeout(resolve,ms,'done'); })) } timeout(100).then(value => console.log(value));
Promise中调用了一个setTimeout方法,并会定时触发resolve方法,并传入参数done。
最后程序输出done。
Promise的执行顺序Promise一经创建就会立马执行。但是Promise.then中的方法,则会等到一个调用周期过后再次调用,我们看下面的例子:
let promise = new Promise(((resolve, reject) => { console.log('Step1'); resolve(); })); promise.then(() => { console.log('Step3'); }); console.log('Step2'); 输出: Step1 Step2 Step3
async和awaitPromise当然很好,我们将回调地狱转换成了链式调用。我们用then来将多个Promise连接起来,前一个promise resolve的结果是下一个promise中then的参数。
链式调用有什么缺点呢?
比如我们从一个promise中,resolve了一个值,我们需要根据这个值来进行一些业务逻辑的处理。
假如这个业务逻辑很长,我们就需要在下一个then中写很长的业务逻辑代码。这样让我们的代码看起来非常的冗余。
那么有没有什么办法可以直接返回promise中resolve的结果呢?
答案就是await。
当promise前面加上await的时候,调用的代码就会停止直到 promise 被解决或被拒绝。
注意await一定要放在async函数中,我们来看一个async和await的例子:
const logAsync = () => { return new Promise(resolve => { setTimeout(() => resolve('小马哥'), 5000) }) }
上面我们定义了一个logAsync函数,该函数返回一个Promise,因为该Promise内部使用了setTimeout来resolve,所以我们可以将其看成是异步的。
要是使用await得到resolve的值,我们需要将其放在一个async的函数中:
const doSomething = async () => { const resolveValue = await logAsync(); console.log(resolveValue); }
async的执行顺序await实际上是去等待promise的resolve结果我们把上面的例子结合起来:
const logAsync = () => { return new Promise(resolve => { setTimeout(() => resolve('小马哥'), 1000) }) } const doSomething = async () => { const resolveValue = await logAsync(); console.log(resolveValue); } console.log('before') doSomething(); console.log('after')
上面的例子输出:
before
after
小马哥
可以看到,aysnc是异步执行的,并且它的顺序是在当前这个周期之后。
async的特点async会让所有后面接的函数都变成Promise,即使后面的函数没有显示的返回Promise。
const asyncReturn = async () => { return 'async return' } asyncReturn().then(console.log)
因为只有Promise才能在后面接then,我们可以看出async将一个普通的函数封装成了一个Promise:
const asyncReturn = async () => { return Promise.resolve('async return') } asyncReturn().then(console.log)
总结promise避免了回调地狱,它将callback inside callback改写成了then的链式调用形式。
但是链式调用并不方便阅读和调试。于是出现了async和await。
async和await将链式调用改成了类似程序顺序执行的语法,从而更加方便理解和调试。
我们来看一个对比,先看下使用Promise的情况:
const getUserInfo = () => { return fetch('/users.json') // 获取用户列表 .then(response => response.json()) // 解析 JSON .then(users => users[0]) // 选择第一个用户 .then(user => fetch(`/users/${user.name}`)) // 获取用户数据 .then(userResponse => userResponse.json()) // 解析 JSON } getUserInfo()
将其改写成async和await:
const getUserInfo = async () => { const response = await fetch('/users.json') // 获取用户列表 const users = await response.json() // 解析 JSON const user = users[0] // 选择第一个用户 const userResponse = await fetch(`/users/${user.name}`) // 获取用户数据 const userData = await userResponse.json() // 解析 JSON return userData } getUserInfo()
可以看到业务逻辑变得更加清晰。同时,我们获取到了很多中间值,这样也方便我们进行调试。