事件循环

基本介绍

JavaScript是一门单线程的编程语言,所以没有真正意义上的并行特性。

为了协调事件处理、页面交互、脚本调用、UI渲染、网络请求等行为对主线程造成的影响,事件循环(event loop)方案应运而生。

事件循环说白了就是一个不断的在等待任务、执行任务的方案。

在JavaScript中,根据执行方式的不同,有2种状态的任务,分别是同步任务和异步任务。

同步任务率先执行,而后执行异步任务,所有的异步任务由2个队列存储,分别是:

  • 微任务队列
  • 宏任务队列

主线程在执行完同步任务后,会不断的从这2个任务队列中按照先进先出的策略取出异步任务并执行。

并且在此期间也会有新的事件不断的加入至各个任务队列中,以此循环往复、永不阻塞。

如下图所示:

任务分类

宏任务包括:

  • setInterval
  • setTimeout
  • setTimmediate Node.Js独有
  • XHR callbackfn
  • event callbackfn
  • requestAnimationFrame
  • UI rendering

微任务包括:

  • Promise.then
  • catch finally
  • process.nextTick Node.Js独有
  • MutationObserver

执行顺序

根据任务的状态,任务的执行优先级也会有所不同,具体执行顺序如下所示:

  1. 同步任务(sync-task)
  2. 微任务(micro-task)
  3. 宏任务(macro-task)

而关于微任务和宏任务的执行,还有更详细的划分:

  • 微任务队列中一旦有任务,将全部执行完成后再执行宏任务
  • 宏任务队列中的任务在执行完成后,会检查微任务队列中是否有新添加的任务,如果有,那么将执行微任务队列中所有新添加的任务,如果没有则继续执行下一个宏任务

如下图所示:

代码测试:

  1. "use strict";
  2. // 宏任务,每5s添加一个微任务并执行
  3. setInterval(() => {
  4. async function foo() {
  5. return "micro-task"
  6. }
  7. async function bar() {
  8. let result = await foo();
  9. console.log(result);
  10. }
  11. bar();
  12. }, 5000);
  13. // 宏任务,每1s执行一次
  14. setInterval(() => { console.log("macro-task"); }, 1000);
  15. // 同步任务
  16. (() => {
  17. console.log("hello world");
  18. })();

测试结果,虽然同步任务的代码在最下面,但是它会最先执行,而每添加一个微任务时,宏任务的执行会被插队:

Promise

认识Promise

Promise是ES6中出现的新功能,用于在JavaScript中更加简单的实现异步编程。

我们可以使用new Promise()创建出一个Promise对象,它接收一个执行器函数,该函数需要指定resolve和reject参数用于改变当前Promise对象的执行状态。

由于Promise对象中执行器代码是属于同步任务,所以他会率先的进行执行,一个Promise对象拥有以下几种状态:

  • fulfilled:任务完成、使用resolve改变了任务状态
  • rejected:任务失败、使用reject改变了任务状态,或任务执行中抛出了异常
  • pending:正在等待、未使用resolve或reject改变任务状态

注意,每个Promise对象的状态只允许改变一次!不可以多次更改。

示例如下。

1)Promise中执行器任务是同步任务,所以会率先执行:

  1. "use strict";
  2. setInterval(() => { console.log("macro task 3"); }, 1000)
  3. let task = new Promise((resolve, reject) => {
  4. console.log("sync task 1");
  5. });
  6. console.log("sync task 2");
  7. // sync task 1
  8. // sync task 2
  9. // macro task 3

2)使用resolve改变Promise对象的状态为fulfilled:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. let x = Math.floor(Math.random() * 100) + 1;
  4. let y = Math.floor(Math.random() * 100) + 1;
  5. let result = x + y;
  6. // 返回结果为resolve()中的值
  7. resolve(result);
  8. });
  9. console.log(task);
  10. // Promise {<fulfilled>: 83}

3)使用reject改变Promise对象的状态为rejected, 它将引发一个异常:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. let x = Math.floor(Math.random() * 100) + 1;
  4. let y = Math.floor(Math.random() * 100) + 1;
  5. let result = x + y;
  6. // 返回结果为reject()中的值
  7. reject("error!")
  8. });
  9. console.log(task);
  10. // Promise {<rejected>: "error!"}
  11. // Uncaught (in promise) error!

4)如果未使用resolve或reject改变Promise对象状态,那么该任务的状态将为pending:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. let x = Math.floor(Math.random() * 100) + 1;
  4. let y = Math.floor(Math.random() * 100) + 1;
  5. let result = x + y;
  6. });
  7. console.log(task);
  8. // Promise {<pending>}

then()

我们可以在Promise对象后,添加一个用于处理任务状态的回调then()方法。

then()方法只有在Promise对象状态为fulfilled或者rejected时才会进行执行,它具有2个参数,接收2个回调函数:

  • onfulfilled:Promise对象状态为fulfilled将执行该函数,具有1个参数value,接收Promise任务中resolve()所传递的值
  • onrejected:Promise对象状态为rejected将执行该函数,具有1个参数reason,接收Promise任务中reject()或异常发生时所传递的值

此外,then()方法是属于微任务,所以他会插在宏任务之前进行执行。

代码示例如下:

1)Promise对象状态为fulfilled,运行then()方法的第1个回调函数:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. resolve("success");
  4. }).then(
  5. value => {
  6. console.log(value);
  7. },
  8. reason => {
  9. console.log(reason);
  10. });
  11. // success

2)Promise对象状态为rejected,运行then()方法的第2个回调函数:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. throw new Error("error");
  4. }).then(
  5. value => {
  6. console.log(value);
  7. },
  8. reason => {
  9. console.log(reason);
  10. });
  11. // error

then()链式调用

其实每一个then()都将返回一个全新的Promise,默认情况下,该Promise的状态是fulfilled。

此时就会产生一种链式关系,每一个then()都将返回一个新的Promise对象,而每个then()的作用又都是处理上个Promise对象的状态。

这意味着我们可以无限的链式排列then(),如下所示:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value);
  9. return value
  10. },
  11. reason => {
  12. console.log(reason);
  13. })
  14. .then(
  15. value => {
  16. console.log("then2 fulfilled", value);
  17. return value
  18. },
  19. reason => {
  20. console.log(reason);
  21. })
  22. .then(
  23. value => {
  24. console.log("then3 fulfilled", value);
  25. return value
  26. },
  27. reason => {
  28. console.log(reason);
  29. });
  30. // first Promise task status is fulfilled
  31. // then1 fulfilled success
  32. // then2 fulfilled success
  33. // then3 fulfilled success

then()的返回值

要想真正的了解链式调用,就必须搞明白每个then()在不同状态下的返回值对下一个then()的影响。

具体情况如下所示:

1)当前then()无返回值,则当前Promise状态则为fulfilled。

下一个then()的onfulfilled回调函数参数value为undefined:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value); // success
  9. },
  10. reason => {
  11. console.log(reason);
  12. })
  13. .then(
  14. value => {
  15. console.log("then2 fulfilled", value); // undefined
  16. },
  17. reason => {
  18. console.log(reason);
  19. });
  20. // first Promise task status is fulfilled
  21. // then1 fulfilled success
  22. // then2 fulfilled undefined

2)当前then()有返回值,则当前Promise状态则为fulfilled。

下一个then()的onfulfilled回调函数参数value为当前then()的返回值:

代码示例:

  1. let task = new Promise((resolve, reject) => {
  2. console.log("first Promise task status is fulfilled");
  3. resolve("success");
  4. })
  5. .then(
  6. value => {
  7. console.log("then1 fulfilled", value); // success
  8. return "then1 value"
  9. },
  10. reason => {
  11. console.log(reason);
  12. })
  13. .then(
  14. value => {
  15. console.log("then2 fulfilled", value); // then1 value
  16. },
  17. reason => {
  18. console.log(reason);
  19. });
  20. // first Promise task status is fulfilled
  21. // then1 fulfilled success
  22. // then2 fulfilled then1 value

3)当前then()有返回值,且返回了一个状态为fulfilled的Promise对象。

下一个then()的onfulfilled回调函数参数value为当前then()中被返回Promise里resolve()所传递的值:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value); // success
  9. return new Promise((resolve, reject) => {
  10. resolve("then1 Promise success")
  11. })
  12. },
  13. reason => {
  14. console.log(reason);
  15. })
  16. .then(
  17. value => {
  18. console.log("then2 fulfilled", value); // then1 Promise success
  19. },
  20. reason => {
  21. console.log(reason);
  22. });
  23. // first Promise task status is fulfilled
  24. // then1 fulfilled success
  25. // then2 fulfilled then1 Promise success

4)当前then()有返回值,且返回了一个状态为rejected的Promise对象。

下一个then()的onrejected回调函数参数reason为当前then()中被返回Promise里reject()所传递的值,或者是被返回Promise里抛出异常的值:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value); // success
  9. return new Promise((resolve, reject) => {
  10. reject("then1 Promise error")
  11. })
  12. },
  13. reason => {
  14. console.log(reason);
  15. })
  16. .then(
  17. value => {
  18. console.log("then2 fulfilled", value);
  19. },
  20. reason => {
  21. console.log(reason); // then1 Promise error
  22. });
  23. // first Promise task status is fulfilled
  24. // then1 fulfilled success
  25. // then1 Promise error

5)当前then()有返回值,且返回了一个状态为pending的Promise对象。下一个then()则必须等待当前then()中被返回Promise对象状态发生改变后才能继续执行:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value); // success
  9. return new Promise((resolve, reject) => {
  10. console.log("pending");
  11. })
  12. },
  13. reason => {
  14. console.log(reason);
  15. })
  16. .then(
  17. value => {
  18. console.log("then2 fulfilled", value);
  19. },
  20. reason => {
  21. console.log(reason);
  22. });
  23. // first Promise task status is fulfilled
  24. // then1 fulfilled success
  25. // pending

另外,如果在代码执行时抛出了异常,那么返回的Promise对象状态则为rejected,下一个then()的onrejected回调函数参数reason为当前then()中抛出异常的值,这里不再进行演示。

then()穿透

then()是具有穿透功能的,当一个then()没有指定需要被执行的回调函数时,它将继续冒泡向下传递:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then()
  7. .then(
  8. value => {
  9. console.log("then2 fulfilled", value);
  10. },
  11. reason => {
  12. console.log(reason);
  13. });
  14. // first Promise task status is fulfilled
  15. // then2 fulfilled success

catch()

每个then()都可以指定onrejected回调函数用于处理上一个Promise状态为rejected的情况。如果每个then()都进行这样的设置会显得很麻烦,所以我们只需要使用catch()即可。

catch()可以捕获之前所有Promise的错误执行,故建议将catch()放在最后。

catch()需要指定一个回调函数onrejected,具有1个参数reason,接收Promise任务中reject()或异常发生时所传递的值。

错误是冒泡传递的,如果没有任何一个then()定义onrejected的回调函数,那么错误将一直冒泡到catch()处进行处理:

代码示例:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value);
  9. return value
  10. }
  11. )
  12. .then(
  13. value => {
  14. console.log("then2 rejected", value);
  15. throw new Error("error");
  16. })
  17. .then(
  18. value => {
  19. console.log("then3 ...", value);
  20. }
  21. )
  22. .catch(
  23. reason => {
  24. console.log(reason);
  25. });
  26. // first Promise task status is fulfilled
  27. // then1 fulfilled success
  28. // then2 rejected success
  29. // Error: error

finally()

finally()是无论任务处理成功或者失败都会执行,因此建议将它放在链式调用的最后面。

它需要指定一个回调函数onfinally,该回调函数没有任何参数:

  1. "use strict";
  2. let task = new Promise((resolve, reject) => {
  3. console.log("first Promise task status is fulfilled");
  4. resolve("success");
  5. })
  6. .then(
  7. value => {
  8. console.log("then1 fulfilled", value);
  9. return value
  10. }
  11. )
  12. .catch(
  13. reason => {
  14. console.log(reason);
  15. }
  16. )
  17. .finally(
  18. () => {
  19. console.log("run");
  20. }
  21. );
  22. // first Promise task status is fulfilled
  23. // then1 fulfilled success
  24. // run

扩展方法

resolve()

resolve()方法用于快速返回一个状态为fulfilled的Promise对象,生产环境中使用较少:

  1. "use strict";
  2. let task = Promise.resolve("success");
  3. console.log(task);
  4. // Promise {<fulfilled>: "success"}

reject()

reject()方法用于快速返回一个状态为rejected的Promise对象,生产环境中使用较少:

  1. "use strict";
  2. let task = Promise.reject("error");
  3. console.log(task);
  4. // Promise {<rejected>: "error"}
  5. // Uncaught (in promise) error

all()

all()方法用于一次同时执行多个异步任务,并且必须确保这些任务是成功的。

  • all()方法接收的参数必须是可迭代类型,如Array、map、set
  • 任何一个Promise状态为rejected,都将调用catch()方法
  • 当所有任务成功执行后,将返回一个包含所有任务的执行结果数组

all()方法应用场景还是非常广泛的,如我们需要使用Ajax请求后端的书籍与价格信息时,不论是书籍获取失败还是价格获取失败,都将认为此次任务的失败。

示例如下:

  1. "use strict";
  2. const getBookNameTask = new Promise((resolve, reject) => {
  3. // 模拟请求后端的书籍名称,需要花费3s
  4. setTimeout(() => {
  5. resolve(JSON.stringify(
  6. ["HTML", "CSS", "JavaScript"]
  7. ))
  8. }, 3000);
  9. });
  10. const getBookPriceTask = new Promise((resolve, reject) => {
  11. // 模拟请求后端的书籍价格,需要花费5s
  12. setTimeout(() => {
  13. resolve(JSON.stringify(
  14. [98, 120, 40]
  15. ))
  16. }, 5000);
  17. })
  18. // 执行任务
  19. Promise.all(
  20. [getBookNameTask, getBookPriceTask]
  21. )
  22. .then(value => {
  23. // 书籍和价格全部获取后才执行这里
  24. // value = ["[\"HTML\",\"CSS\",\"JavaScript\"]", "[98,120,40]"]
  25. const bookNameArray = JSON.parse(value[0]);
  26. const bookPriceArray = JSON.parse(value[1]);
  27. const bookAndNameMap = new Map();
  28. for (let i = 0; i < bookNameArray.length; i++) {
  29. bookAndNameMap.set(bookNameArray[i], bookPriceArray[i]);
  30. }
  31. console.log(bookAndNameMap);
  32. })
  33. .catch(reason => {
  34. // 任何一个没获取到都执行这里
  35. console.log(reason);
  36. });

allSettled()

allSettled()方法和all()方法相似,都是用于同时执行多个异步任务,但是它并不关心所有任务是否都执行成功。

allSettled()的状态只会是fulfilled:

  1. "use strict";
  2. const getBookNameTask = new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. reject("error! Can't query all books name")
  5. }, 3000);
  6. });
  7. const getBookPriceTask = new Promise((resolve, reject) => {
  8. setTimeout(() => {
  9. reject("error! Can't query all books price")
  10. }, 5000);
  11. })
  12. // 执行任务
  13. Promise.allSettled(
  14. [getBookNameTask, getBookPriceTask]
  15. )
  16. .then(value => {
  17. // 不管怎样都会执行这里
  18. console.log("run me");
  19. })

race()

race()也可同时执行多个任务,它仅会返回最快完成任务的执行结果。

  • 以最快返回的任务结果为准
  • 如果最快返回的任务状态为rejected,那么race()的状态也将视为rejected,此时将执行catch()方法

race()方法用的也比较多,如我们需要加载一些图片,这些图片在多个服务端上都有存储,但为了提高用户体验我们需要根据用户所在的地理位置选择最近的服务器,此时race()就派上了用场:

  1. "use strict";
  2. const getCacheImages = new Promise((resolve, reject) => {
  3. setTimeout(() => {
  4. resolve("get cache images success!!");
  5. }, 1000);
  6. })
  7. const getWebImages = new Promise((resolve, reject) => {
  8. setTimeout(() => {
  9. resolve("get web images success!!");
  10. }, 3000);
  11. })
  12. // 创建任务
  13. Promise.race(
  14. [getCacheImages, getWebImages]
  15. )
  16. .then(value => {
  17. console.log(value);
  18. })
  19. .catch(reason => {
  20. console.log(reason);
  21. })
  22. // get cache images success!!

async&await

async

async其实是new Promise()的语法糖简写形式。

在某一个函数前面加上async,运行该函数时将会返回一个Promise对象。

  • 没有return:返回的Promise对象状态为fulfilled,下一个then()的onfulfilled回调函数参数value为undefined
  • 直接return:返回的Promise对象状态为fulfilled,下一个then()的onfulfilled回调函数参数value为当前async函数的返回值
  • return了一个状态为fulfilled的Promise对象:下一个then()的onfulfilled回调函数参数value为当前async函数中被返回Promise里resolve()所传递的值
  • return了一个状态为rejected的Promise对象:下一个then()的onrejected回调函数参数reason为当前async函数中被返回Promise里reject()所传递的值,或者是被返回Promise里抛出异常的值
  • 运行时抛出异常:返回的Promise对象状态为rejected,下一个then()的onrejected回调函数参数reason为当前async函数中抛出异常的值

示例演示:

  1. "use strict";
  2. async function task() {
  3. return "success"
  4. }
  5. task().then(value => {
  6. console.log(value);
  7. });
  8. // success

await

await其实是then()的另一种写法,它只能在async函数中使用。

  • await后面一般都会跟上一个Promise对象,如果不是Promise对象,将直接返回该值。
  • await使用必须在async函数中
  • await作为then()的语法糖形式,使用它编写代码将使代码变的更加优雅

如下所示,我们有3个任务,这3个任务必须是先通过用户ID获取人员姓名、再通过用户ID获取信息ID、最后再通过用户ID获取人员信息。

如果你用纯Promise+then()的方式进行代码编写,它将是这样的:

  1. "use strict";
  2. const idAndName = new Map([
  3. [1, "Jack"],
  4. [2, "Tom"],
  5. [3, "Mary"],
  6. ]);
  7. const personnelInformation = new Map([
  8. [1, { gender: "female", age: 18, addr: "TianJin", desc: "my name is Mary" }],
  9. [2, { gender: "male", age: 21, addr: "ShangHai", desc: "my name is Tom" }],
  10. [3, { gender: "male", age: 18, addr: "BeiJing", desc: "my name is Jack" }],
  11. ]);
  12. const nameAndMessage = new Map([
  13. [1, 3],
  14. [2, 2],
  15. [3, 1],
  16. ])
  17. function getUserMessage(id) {
  18. let userName, messageId, message, str;
  19. new Promise((resolve, reject) => {
  20. // 获取姓名
  21. if (idAndName.has(id)) {
  22. userName = idAndName.get(id);
  23. resolve();
  24. }
  25. reject(`no information id : ${id}`);
  26. })
  27. .then(() => {
  28. // 获取关系
  29. messageId = nameAndMessage.get(id);
  30. })
  31. .then(() => {
  32. // 获取信息
  33. message = personnelInformation.get(messageId);
  34. })
  35. .then(() => {
  36. // 进行渲染
  37. str = `name : ${userName}</br>`;
  38. for (let [k, v] of Object.entries(message)) {
  39. str += `${k} : ${v}</br>`;
  40. }
  41. document.write(str)
  42. })
  43. .catch(reason => {
  44. document.write(`<p style="color:red">${reason}</p>`);
  45. })
  46. }
  47. getUserMessage(3);

如果你使用async+awit的方式编写,那么它的逻辑就会清楚很多:

  1. "use strict";
  2. const idAndName = new Map([
  3. [1, "Jack"],
  4. [2, "Tom"],
  5. [3, "Mary"],
  6. ]);
  7. const personnelInformation = new Map([
  8. [1, { gender: "female", age: 18, addr: "TianJin", desc: "my name is Mary" }],
  9. [2, { gender: "male", age: 21, addr: "ShangHai", desc: "my name is Tom" }],
  10. [3, { gender: "male", age: 18, addr: "BeiJing", desc: "my name is Jack" }],
  11. ]);
  12. const nameAndMessage = new Map([
  13. [1, 3],
  14. [2, 2],
  15. [3, 1],
  16. ])
  17. // 获取姓名
  18. async function getName(id) {
  19. if (idAndName.has(id)) {
  20. return idAndName.get(id);
  21. }
  22. throw new Error(`no information id : ${id}`);
  23. }
  24. // 获取关系
  25. async function getRelation(id) {
  26. return nameAndMessage.get(id);
  27. }
  28. // 获取信息
  29. async function getMessage(messageId) {
  30. return personnelInformation.get(messageId);
  31. }
  32. // 入口函数,进行渲染
  33. async function getUserMessage(id) {
  34. try {
  35. let userName = await getName(id); // 必须等待该函数执行完成才会继续向下执行
  36. let messageId = await getRelation(id);
  37. let message = await getMessage(messageId);
  38. let str = `name : ${userName}</br>`;
  39. for (let [k, v] of Object.entries(message)) {
  40. str += `${k} : ${v}</br>`;
  41. }
  42. document.write(str)
  43. } catch (e) {
  44. document.write(`<p style="color:red">${e}</p>`);
  45. }
  46. }
  47. getUserMessage(3);

异常处理

async+await的异常处理推荐使用try+catch语句将所有执行代码进行包裹,它将处理所有可能出现的异常,相当于在链式调用的最后面加上catch()方法:

  1. "use strict";
  2. async function task01() {
  3. console.log("run task 01");
  4. }
  5. async function task02() {
  6. throw new Error("task02 error");
  7. console.log("run task 02");
  8. }
  9. async function task03() {
  10. console.log("run task 03");
  11. }
  12. async function main() {
  13. try {
  14. await task01();
  15. await task02();
  16. await task03();
  17. } catch (e) {
  18. console.log(e);
  19. }
  20. }
  21. main();

也可以在主函数外部使用catch()方法来处理异常,但是我并不推荐这么做。

  1. "use strict";
  2. async function task01() {
  3. console.log("run task 01");
  4. }
  5. async function task02() {
  6. throw new Error("task02 error");
  7. console.log("run task 02");
  8. }
  9. async function task03() {
  10. console.log("run task 03");
  11. }
  12. async function main() {
  13. await task01();
  14. await task02();
  15. await task03();
  16. }
  17. main().catch(reason => {
  18. console.log(reason);
  19. });

除此之外,你也可以使用try+catch语句块对单独的async函数语句块进行处理,预防可能出现的异常。

掌握JavaScript中的Promise,实现异步编程的更多相关文章

  1. 在Python中使用asyncio进行异步编程

    对于来自JavaScript编码者来说,异步编程不是什么新东西,但对于Python开发者来说,async函数和future(类似JS的promise)可不是那么容易能理解的. Concurrency ...

  2. 快速入门上手JavaScript中的Promise

    当我还是一个小白的时候,我翻了很多关于Promise介绍的文档,我一直没能理解所谓解决异步操作的痛点是什么意思 直到我翻了谷歌第一页的所有中文文档我才有所顿悟,其实从他的英文字面意思理解最为简单粗暴 ...

  3. javascript中的promise和deferred:实践(二)

    javascript中的promise和deferred:实践(二) 介绍: 在第一节呢,我花了大量的时间来介绍promises和deferreds的理论.现在呢,我们来看看jquery中的promi ...

  4. Promise和异步编程

    前面的话 JS有很多强大的功能,其中一个是它可以轻松地搞定异步编程.作为一门为Web而生的语言,它从一开始就需要能够响应异步的用户交互,如点击和按键操作等.Node.js用回调函数代替了事件,使异步编 ...

  5. Promise对象 异步编程

    Promise 的含义 Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大.所谓Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是 ...

  6. JavaScript中的Promise【期约】[未完成]

    JavaScript中的Promise[期约] 期约主要有两大用途 首先是抽象地表示一个异步操作.期约的状态代表期约是否完成. 比如,假设期约要向服务器发送一个 HTTP 请求.请求返回 200~29 ...

  7. 通过一道笔试题浅谈javascript中的promise对象

    因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...

  8. Javascript中的Promise

    Promise定义 Promise是CommonJs的规范之一,包含resolve,reject,done,fail,then等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套.异步在web开发中 ...

  9. 彻底理解Javascript 中的 Promise(-------------------------------***---------------------------------)

    ES6原生提供了 Promise 对象. 到底是何方妖怪呢?打出来看看: 所谓 Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个 ...

随机推荐

  1. 1、centos7修改网卡名称为传统的eth0

    [root@localhost ~]# cd /etc/sysconfig/network-scripts/ [root@localhost network-scripts]#mv ifcfg-ens ...

  2. js动态添加的html绑定事件

    使用场景:网站上ul里面的li数据需要从后台数据查询出来即通过js添加数据.然后监听点击li点击事件. 添加数据代码: for(var i = 0; i < table.length; i++) ...

  3. 组建Redis集群遇到`GLIBC_2.14' not found和ps -ef 不显示用户名

    RHEL6.9组建Redis sentinel集群遇到两个问题 今天在组件Redis sentinel 集群时,遇到两个问题,之前已经组建多次,都没碰到类似问题,在解决这两个问题时,耗费些时间. 问题 ...

  4. Springboot:单元测试@FixMethodOrder注解指定测试方法的执行顺序

    我们在写JUnit测试用例时,有时候需要按照定义顺序执行我们的单元测试方法,比如如在测试数据库相关的用例时候要按照测试插入.查询.删除的顺序测试.如果不按照这个顺序测试可能会出现问题,比如删除方法在前 ...

  5. buu [V&N2020 公开赛]strangeCpp

    拖入ida,静态调试一下,本来想动调的,发现一直缺dll.没办法,只能头铁,静态 找到主函数,然后并没有发现什么,找了半天,没结果,后面也是看了大佬wp,才找到解决方式,感觉这种只能通过动调来找到关键 ...

  6. scrapy 配置文件的详细描述

    # 项目名称 BOT_NAME = 'anjvke' # 爬虫文件所在目录 SPIDER_MODULES = ['anjvke.spiders'] # 创建爬虫文件的模板,创建好的爬虫文件会放在此目录 ...

  7. python 16篇 多线程和多进程

    1.概念 线程.进程 进程 一个程序,它是一组资源的集合 一个进程里面默认是有一个线程的,主线程 多进程是可以利用多核cpu的线程 最小的执行单位 线程和线程之间是互相独立的 主线程等待子线程执行结束 ...

  8. SELECT SQL

    替换换行符: update qgnews set article_url=REPLACE(article_url,char(10),'') 替换回车符: update qgnews set artic ...

  9. vs2013恢复默认设置

    选择 工具->import or export settings(工具->导入导出设置),选择最下面一项即可

  10. [WPF] 使用 Visual Studio App Center 持续监视应用使用情况和问题

    1. 什么是AppCenter Visual Studio App Center 是几个常见移动开发和云集成服务(如持续集成.持续交付和自动 UI 测试等服务)的集合. 这些 App Center 服 ...