一、快速理解
1、promise
promise 提供了一种异步处理的操作,避免了嵌套地狱的出现。

// 一个传统写法的嵌套地狱
function qiantaodiyu() {
// 模拟一个异步操作
const syncTask = (content, time, resolve) => {

setTimeout(() => {
  console.log(content, time);
  resolve && resolve(content);
}, time);

};

// 传统的异步嵌套
syncTask('执行 task1', 100, () => {

syncTask('执行 task2', 300, () => {
  syncTask('执行 task3', 100, () => {
    console.log(chalk.green('这是嵌套地狱最后一个回调的内容'))
  })
});

});
}

// 以上的写法改成 promise 后的处理
function promiseDemo() {
// 用 promise 编写一个异步操作
const promiseTask = (content, time) => {

return new Promise((resolve) => {
  setTimeout(() => {
    console.log(content, time);
    resolve && resolve(content);
  }, time);
});

};

// 用 promise 的 then 来避免异步嵌套
promiseTask('执行 task1', 100)

.then((result) => {
  console.log('task1 resolve result:', result);
  return promiseTask('执行 task2', 300);
})
.then((result) => {
  console.log('task2 resolve result:', result);
  return promiseTask('执行 task3', 300);
});

}

2、async 与 await
async 与 await 最重要的一点就是能够让 promise 异步操作变成同步的操作。这样所有异步任务就都可以用 promise 去编写,然后可以并行处理时就用 promise.all ,如果要串行处理时就用 async 与 await 处理。具体示例如下。

// 用 setTimeout 模拟一个异步操作
function timeoutPromise(content, time) {
return new Promise((resolve) => {

setTimeout(() => {
  console.log(content, time);
  resolve && resolve(content);
}, time);

});
}

// 要并行操作时就采用这种写法
/* 注意:promise.all 的 resolve 是所有异步的 resolve 都完成后才执行,回调结果是一个数组,
包含所有异步的回调的结果。而 reject 是第一个出错的时候就会执行,回调结果是第一个异步的错误信息。
因此,在出错的时候,其他的异步并不会停止,而是会继续执行。
*/
function parallelTask() {
const task1 = timeoutPromise('执行 task1', 100);
const task2 = timeoutPromise('执行 task2', 300);
const task3 = timeoutPromise('执行 task3', 100);
const task4 = timeoutPromise('执行 task4', 400);
const task5 = timeoutPromise('执行 task5', 100);

Promise.all([task1, task2, task3, task4, task5])

.then((values) => {
  console.log(
    chalk.green(`所有任务完成后的操作,最后返回的内容是:${values}`)
  );
})
.catch((err) => {
  console.log(chalk.red('这是出错时的处理', err));
});

}

// 要串行处理时就采用这种写法
async function seriesTask() {
try {

const task1 = await timeoutPromise('执行 task1', 100);
const task2 = await timeoutPromise('执行 task2', 300);
const task3 = await timeoutPromise('执行 task3', 100);
const task4 = await timeoutPromise('执行 task4', 400);
const task5 = await timeoutPromise('执行 task5', 100);

const values = [task1, task2, task3, task4, task5]

console.log(chalk.green(`这是串行任务完成后的结果,内容是:${values.toString()}`));

} catch (error) {

console.log(chalk.red('这是出错时的处理', error))

}
}

二、相关资料
建议按照以下的顺序进行了解:
1、使用 promise
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
2、promise
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise#%E5%88%9B%E5%BB%BApromise
3、async 与 await
https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Asynchronous/Async_await

三,以前的学习笔记

async 与 await

// 这个函数是一个异步的操作
function resolveAfter2Seconds() {
return new Promise(resolve => {

setTimeout(() => {
  resolve('resolved');
}, 2000);

});
}

// await 让上面的异步函数进入到同步的反馈机制中,只在 async 定义的函数下才有效
async function asyncCall() {
console.log('calling');
const result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}

asyncCall();

  • 特别注意的点:async 与 await 只在当前函数里有效,比如以下两个例子:
    例子一,async 未定义

/**

  • 注意这里的 fetch 是一个 promise 来的,所以这里的
  • await 保证了后面的内容可以在 fetch 执行完后再处理。
  • 而此时 response 获取到的是 fetch 执行后的返回值
    */

async function postData(url = '', data = {}) {
const response = await fetch(url, {

method: 'POST', 
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),

});

console.log("response", response);

if (response.ok) {

return response.json();

}
}

/**

  • 由于 query 这里并没有定义 async 和 await ,所以即使 postData 自身有这个定义,
  • 在 query 里,postData 还是一个异步的操作,所以此时 data 获取到的并不是查询结果,而是一个 promise 对象
    */

function query() {
let resJson = postData('/material/query');
console.log('resJson', resJson);
}

document.querySelector('#test-query').addEventListener('click', () => {
console.log('test-query');
query();
console.log('test-query end');
})

例子二:

/**

  • 注意这里的 fetch 是一个 promise 来的,所以这里的
  • await 保证了后面的内容可以在 fetch 执行完后再处理。
  • 而此时 response 获取到的是 fetch 执行后的返回值
    */

async function postData(url = '', data = {}) {
const response = await fetch(url, {

method: 'POST', 
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data),

});

console.log("response", response);

if (response.ok) {

return response.json();

}
}

/**

  • query 这里定义了 async 和 await ,所以此时 data 就是 postData 的查询结果。
    */

async function query() {
let resJson = await postData('/material/query');
console.log('resJson', resJson);
}

/**

  • 注意这一层也得用 async ,否则获取到的还是一个 promise 对象
    */

async function testQuery(){
console.log('test-query');
await query();
console.log('test-query end');
}
document.querySelector('#test-query').addEventListener('click', testQuery)

promise

  • 参考资料:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
  • 为什么要有 promise
    一层层的回调函数会导致整体代码难以阅读,而用 promise 可以用链式的方式把这些内容给呈现出现,更有利于理解与阅读。
  • promise 中最重要的理念就是:
    连续执行两个或者多个异步操作,在上一个操作执行成功之后,开始下一个的操作,并带着上一步操作所返回的结果。
  • 要理解 promise 主要得理解两块内容,第一块是定义 promise,第二块是使用 promise。

定义 promise

定义一个 promise 主要通过以下的方式进行定义,这个定义中,resolve, reject 这两个参数主要用来处理回调内容,前者是处理成功后的回调,后者是处理失败时的回调。

new Promise((resolve, reject) => {

console.log('初始化');

resolve();

})

再加一层函数将上面的函数包裹起来后,就可以把这个定义的行为做成一个公用的方法,比如以下:

function promiseObj(param) {
return new Promise((resolve, reject) => {

console.log("初始化");
setTimeout(() => {
  const result = param.value + 1;

  resolve(result);
}, 3000);

});
}

// 定义一个 promise
const promiseExample = promiseObj({ value: 1 });
promiseExample.then((result) => {
console.log(result);
});

无论是多复杂的 promise 定义都是按照上面的这两种方式进行定义的。

使用 promise

同一个 promise 可以有多个 then 配置,多个 promise 混合使用则是通过 then 中的 return 来处理,具体示例如下:
同一个 promise :

function promiseOne() {

      return new Promise((resolve, reject) => {
        console.log("promiseOne 初始化");

        resolve('promiseOne');
      });
    }

// 同一个 promise 可以有多个 then 和 catch,当其中一个 then 抛出错误时,then 与 catch 中间的 then 会被跳过

    promiseOne()
      .then((curObj) => {
        throw new Error("有哪里不对了");
        // 抛出错误后,当前函数不会再执行,但后面的 then  与 catch 会继续执行

        console.log(`${curObj} :执行「这个」`);
      })
      .then((curObj) => {
        // 当前面发生错误时,这里会被跳过
        console.log(`${curObj} :执行「catch 前的 then」`);
      })
      .catch((curObj) => {
        console.log(`${curObj} :执行「那个」`);
      })
      .then((curObj) => {
        console.log(`${curObj} :执行「这个」,无论前面发生了什么`);
      });

多个 promise 混合使用:

function promiseOne() {

      return new Promise((resolve, reject) => {
        console.log("promiseOne 初始化");

        resolve('promiseOne');
      });
    }

    function promiseTwo() {
      return new Promise((resolve, reject) => {
        console.log("promiseTwo 初始化");

        resolve('promiseTwo');
      });
    }

    function promiseThird() {
      return new Promise((resolve, reject) => {
        console.log("promiseThird 初始化");

        resolve('promiseThird');
      });
    }

// 这是多个 promise 混合使用的场景,通过 return 的方式变换下一个 promise 对象

    promiseOne()
      .then((curObj) => {
        console.log(`执行了 ${curObj}`);
        return promiseTwo();
      })
      .then((curObj) => {
        console.log(`执行了 ${curObj}`);
        return promiseThird();
      })
      .then((curObj) => {
        console.log(`执行了 ${curObj}`);
        console.log(`整个链条结束`);
      });

标签: none

添加新评论