最近看 JS 代码,对于 Promise 相关写法不是很熟悉,因此梳理了一下相关概念
Javascript 中的函数写法
在异步操作中会用到的回调函数通常使用匿名函数的写法,这里先复习一下 Javascript 中各种函数写法
function hello () {
return "Hello world!"
}
// with parameters
function hello (name) {
return "Hello " + name + "!"
}
// 匿名函数
function (name) {
return "Hello " + name + "!"
}
// Arrow function
hello = () => { // 等价于 hello = function() {
return "Hello World!";
}
// 省略 `{}` 和 `return`
hello = (name) => "Hello " + name + "!";
hello = (firstName, lastName) => "Hello " + firstName + " " + lastName + "!";
// 只有一个参数时,括号也可以省略
hello = name => "Hello " + name + "!";
P.S.:
- 函数只能有一个返回值,如果需要返回多个值,可以把它们放到对象或数组中返回
Promise
Promise 的定义如下:A Promise is an object that represents the result of an asynchronous computation
Javascript 中异步执行的过程通过以下方式实现:
- 函数调用会被放入 Call Stack
- Promise callback function 会被放入 Microtask Queue
setTimeout
,setInterval
等异步 web APIs 会被放入 Task Queue- Event Loop 会一直检查 call stack,当其为空时会将 microtask queue 中的 callback function 放入 call stack,当 call stack 和 microtask queue 均为空时才会处理 task queue
创建 Promise 对象
let myPromise = new Promise((resolve, reject) => {
// do something may not get result immediately
const v = Math.random()
console.log(v)
if ( v > 0.5 ) { // some condition
// case on some condition
// call resolve callback function and pass result data as argument
resolve({ data: 'Here is your data!' })
} else {
// case on other condition
// call reject callback function and pass error as argument
reject(new Error('Network error'))
}
})
console.log("promise defined")
上述代码在 Promise 对象创建时会立即允许里面代码,在调用 resolve(res)/reject(err)
时会改变 Promise 对象的状态,这时 Promise 会进入成功/失败状态
调用 Promise.then
或 Promise.catch
会将里面的 callback 函数放入 microtask queue,等待 Promise 进入成功/失败状态后且 同步代码运行完后调用 callback 函数
// code in the Promise block get executed when created
// code in the `then/catch` block wait until the Promise enter resolved/rejected state
myPromise
.then(result => {
console.log('Data:', result.data)
})
.catch(error => {
console.error('Error:', error.message)
})
定义异步函数
function fetchData() {
return new Promise((resolve, reject) => {
console.log(Date.now() + ": promise start")
const v = Math.random()
if (v > 0.5) {
resolve({ data: "hello" })
} else {
reject(new Error('Network error'))
}
console.log(Date.now() + ": promise end")
})
}
这时 Promise 内部的代码并不是立即执行,而是在调用 fetchData
函数时执行,下面的代码会立即执行 Promise 的内容,并等待 Promise 状态改变后执行传入 then/catch
的回调函数
fetchData()
.then((res) => {
console.log(Date.now() + ": promise resolved")
console.log(res.data)
})
.catch((err) => {
console.log(Date.now() + ": promise rejected")
})
链式调用:传入 .then(callback1)
的回调函数可以返回值,这个值会作为参数被传到下一个 .then(callback2)
的回调函数
let promise = new Promise((resolve, reject) => {
resolve(1)
})
promise
.then(res => {
console.log(res) // 输出 1
return res + 1
})
.then(res => {
console.log(res) // 输出 2
return res + 1
})
.then(res => {
console.log(res) // 输出 3
return res + 1
})
如果回调函数返回了一个 Promise 对象,那么下一个 .then(callback)
同样会等待上一个回调函数的执行
promise
.then(value => {
return new Promise(resolve => {
setTimeout(() => {
resolve(value + 1);
}, 1000);
});
})
.then(value => {
console.log(value); // 输出 2,但是在 1 秒后
});
await/async
是 ES7 中引入的新特性,具体用法如下
async function
关键字定义的函数,自动将返回值包装成一个 Promise,如果正常返回就是 resolved 状态,如果有异常则为 rejected 状态
async function asyncSleep(time) {
setTimeout(() => {
console.log(Date.now() + ": asyncSleep")
}, time * 1000)
}
// 等价于
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log(Date.now() + ": sleep")
}, time * 1000)
resolve()
})
}
await
只能用在用 async
定义的函数内部, 用于暂停执行等待某个 async 函数的返回
function sleep(time) {
return new Promise((resolve, reject) => { setTimeout(() => {
console.log(Date.now() + ": sleep")
}, time * 1000)
resolve()
})
}
async function asyncSleep(time) {
console.log(Date.now() + ": asyncSleep start")
await sleep(time)
console.log(Date.now() + ": asyncSleep end")
}
asyncSleep(1)
.then(() => {
console.log(Date.now() + ": asyncSleep resolved")
})