由Blocking Search动画引出的知识点2
调用含有 setInterval 的函数时异步问题的解决
重点:使用 async/await 与 Promise 对象
在代码中引用
- 引用前(有问题的代码)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25var linearSearch = function (desired_letter, array, flag) {
...
linear_interval = setInterval(function () {
...
if (current_index >= array.length) {
clearInterval(linear_interval);
return -1;
}
...
if (current_value >= desired_letter) {
clearInterval(linear_interval);
...
return current_index;
}
current_index += 1;
}, SEARCH_INTERVAL_TIME/2);
}
// ## Blocking Search
async function startBlockingSearch(desired_letter, array) {
...
const which_block = linearSearch(desired_letter, block_arr, 0);
console.log("which_block = ", which_block);
...
}
这里遇到了 which_block 打印出来始终为 undefined 的问题。
问题解决后的代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27var linearSearch = function (desired_letter, array, flag) {
return new Promise(function(resolve, reject){
...
linear_interval = setInterval(function () {
...
if (current_index >= array.length) {
clearInterval(linear_interval);
resolve(-1);
}
...
if (current_value >= desired_letter) {
clearInterval(linear_interval);
...
resolve(current_index);
}
...
}, SEARCH_INTERVAL_TIME/2);
});
}
// ## Blocking Search
async function startBlockingSearch(desired_letter, array) {
...
const which_block = await linearSearch(desired_letter, block_arr, 0);
console.log("which_block = ", which_block);
...
}需要注意的地方
- 在 async 的函数(这里是 startBlockingSearch 函数)里面引用的函数(这里是 linearSearch 函数)的真正返回值需要用
resolve包裹起来 - 且引用的函数必须再用 return new Promise(function(resolve, reject){…} 嵌套一次
- 在 async 的函数(这里是 startBlockingSearch 函数)里面引用的函数(这里是 linearSearch 函数)的真正返回值需要用
关于Promise对象
一些参考链接
-
主要内容:
Promise 三状态- pending:初始状态,未完成或拒绝
- fulfilled:操作成功完成[Resolved(已完成,又称 Fulfilled)]
rejected:操作失败
pending状态的Promise对象可能被填充了(fulfilled)值,也可能被某种理由(异常信息)拒绝(reject)了。当其中任一种情况出现时,Promise对象的then方法绑定的处理方法(handlers )就会被调用(then方法包含两个参数:onfulfilled和onrejected,它们都是Function类型。当值被填充时,调用then的onfulfilled方法,当Promise被拒绝时,调用then的onrejected方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)
因为Promise.prototype.then和 Promise.prototype.catch方法返回 promises对象自身, 所以它们可以被链式调用.

Promise API
- Promise.resolve() 执行成功
- Promise.reject() 执行失败
- Promise.prototype.then() 递延处理
- Promise.prototype.catch() 异常
-
主要内容:
封装代码与异步代码1
2
3
4
5
6
7new Promise(function (resolve, reject) {
resolve(someValue);
});
写成
Promise.resolve(someValue);捕获同步异常
1
2
3
4
5new Promise(function (resolve, reject) {
throw new Error('悲剧了,又出 bug 了');
}).catch(function(err){
console.log(err);
});
关于async 与 await
一些参考链接
-
注意点:
- async用来申明里面包裹的内容可以进行同步的方式执行,await则是进行执行顺序控制,每次执行一个await,程序都会暂停等待await返回值,然后再执行之后的await。
- await后面调用的函数需要返回一个promise,另外这个函数是一个普通的函数即可,而不是generator。
await只能用在async函数之中,用在普通函数中会报错。
1
2
3
4
5
6
7
8async function dbFuc(db) {
let docs = [{}, {}, {}];
// 报错
docs.forEach(function (doc) {
await db.post(doc);
});
}上面代码会报错,因为 await 用在普通函数之中了。但是,如果将 forEach 方法的参数改成 async 函数,也有问题。
1
2
3
4
5
6
7
8async function dbFuc(db) {
let docs = [{}, {}, {}];
// 可能得到错误结果
docs.forEach(async function (doc) {
await db.post(doc);
});
}上面代码可能不会正常工作,原因是这时三个 db.post 操作将是并发执行,也就是同时执行,而不是继发执行。正确的写法是采用 for 循环。
1
2
3
4
5
6
7async function dbFuc(db) {
let docs = [{}, {}, {}];
for (let doc of docs) {
await db.post(doc);
}
}如果确实希望多个请求并发执行,可以使用 Promise.all 方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = await Promise.all(promises);
console.log(results);
}
// 或者使用下面的写法
async function dbFuc(db) {
let docs = [{}, {}, {}];
let promises = docs.map((doc) => db.post(doc));
let results = [];
for (let promise of promises) {
results.push(await promise);
}
console.log(results);
}
+ await命令后面的 Promise 对象,运行结果可能是 rejected,所以最好把 await 命令放在 try...catch 代码块中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
async function myFunction() {
try {
await somethingThatReturnsAPromise();
} catch (err) {
console.log(err);
}
}
// 另一种写法
async function myFunction() {
await somethingThatReturnsAPromise().catch(function (err){
console.log(err);
});
}
-
- 示例:指定多少毫秒后输出一个值。(指定50毫秒以后,输出”hello world”。)
1
2
3
4
5
6
7
8
9
10
11
12function timeout(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function asyncPrint(value, ms) {
await timeout(ms);
console.log(value)
}
asyncPrint('hello world', 50);
- 示例:指定多少毫秒后输出一个值。(指定50毫秒以后,输出”hello world”。)
理解JavaScript的async/await
这篇很重要
实现效果

动态添加li的方法
1 | for(i=0; i<len; i++) { |