// 1. JS是单线程 解决方式 异步
// 2. 异步的解决方式 事件轮循
// 3. 事件轮循的核心-回调函数
// let arr = [1,34,3]
// let arr2 = arr.sort()
// setTimeout(() => alert(arr2),6000)
// //同步回调函数 异步回调函数
// console.log(arr)
// 回调
// promise
// 异步编程的一种解决方案,比传统的解决方案-回调函数和事件-更合理
// 三种状态
// pending【待定】初始状态
// fulfilled [实现] 操作成功
// rejected 【拒绝】 操作失败
// Promise 是将“生产者代码”和“消费者代码”连接在一起的一个特殊的 JavaScript 对象。用我们的类比来说:这就是就像是“订阅列表”。“生产者代码”花费它所需的任意长度时间来产出所承诺的结果,而 “promise” 将在它(译注:指的是“生产者代码”,也就是下文所说的 executor)准备好时,将结果向所有订阅了的代码开放。
// 这种类比并不十分准确,因为 JavaScipt 的 promise 比简单的订阅列表更加复杂:它们还拥有其他的功能和局限性。但以此开始挺好的。
// Promise 对象的构造器(constructor)语法如下:
// let promise = new promise(传一个函数)
// let xx = Promise(function (resolve, reject) {
// resolve(console.log('xxxxx'))
// });
//
// xx.then(function (res)) {
// console.log("yyyy")
// }
// 传递给 new Promise 的函数被称为 executor。当 new Promise 被创建,executor 会自动运行。它包含最终应产出结果的生产者代码。按照上面的类比:executor 就是“歌手”。
// 它的参数 resolve 和 reject 是由 JavaScript 自身提供的回调。我们的代码仅在 executor 的内部。
// 当 executor 获得了结果,无论是早还是晚都没关系,它应该调用以下回调之一:
// resolve(value) —— 如果任务成功完成并带有结果 value。
// reject(error) —— 如果出现了 error,error 即为 error 对象。
// 所以总结一下就是:executor 会自动运行并尝试执行一项工作。尝试结束后,如果成功则调用 resolve,如果出现 error 则调用 reject。
// 由 new Promise 构造器返回的 promise 对象具有以下内部属性:
// state —— 最初是 "pending",然后在 resolve 被调用时变为 "fulfilled",或者在 reject 被调用时变为 "rejected"。
// result —— 最初是 undefined,然后在 resolve(value) 被调用时变为 value,或者在 reject(error) 被调用时变为 error。
// let promise = new Promise(function (resolve,reject){
// console.log("no")
// // 当 promise 被构造完成时,自动执行此函数
// // 1 秒后发出工作已经被完成的信号,并带有结果 "done"
// setTimeout(() => resolve(console.log("yes")),1000)
// console.log("done")
// });
// executor 被自动且立即调用(通过 new Promise)。
// executor 接受两个参数:resolve 和 reject。这些函数由 JavaScipt 引擎预先定义,因此我们不需要创建它们。我们只需要在准备好(译注:指的是 executor 准备好)时调用其中之一即可。
// // 经过 1 秒的“处理”后,executor 调用 resolve("done") 来产生结果。这将改变 promise 对象的状态:
// let promise1 = new Promise(function (resolve, reject) {
// // 1 秒后发出工作已经被完成的信号,并带有 error
// setTimeout(() => reject(new Error("Whoops")),1000)
// });
// 对 reject(...) 的调用将 promise 对象的状态移至 "rejected":
// 总而言之,executor 应该执行一项工作(通常是需要花费一些时间的事儿),然后调用 resolve 或 reject 来改变对应的 promise 对象的状态。
// 与最初的 “pending” promise 相反,一个 resolved 或 rejected 的 promise 都会被称为 “settled”。
// 这儿只能有一个结果或一个 error
// executor 只能调用一个 resolve 或一个 reject。任何状态的更改都是最终的。
// 所有其他的再对 resolve 和 reject 的调用都会被忽略:
// 这儿的宗旨是,一个被 executor 完成的工作只能有一个结果或一个 error。
// 并且,resolve/reject 只需要一个参数(或不包含任何参数),并且将忽略额外的参数。
// let promise = new Promise(function(resolve, reject) {
// resolve("done");
// reject(new Error("…")); // 被忽略
// setTimeout(() => resolve("…")); // 被忽略
// });
// 以 Error 对象 reject
// // 如果什么东西出了问题, executor 应该调用 reject。这可以使用任何类型的参数来完成(就像 resolve 一样)。但是建议使用 Error 对象(或继承自 Error 的对象)。这样做的理由很快就会显而易见。
// Resolve/reject 可以立即进行,实际上,executor 通常是异步执行某些操作,并在一段时间后调用 resolve/reject,但这不是必须的。我们还可以立即调用 resolve 或 reject,就像这样:
// let promise = new Promise(function (resolve, reject) {
// resolve(123)
// })
// 例如,当我们开始做一个任务时,但随后看到一切都已经完成并已被缓存时,可能就会发生这种情况。
// 这挺好。我们立即就有了一个 resolved 的 promise。
// state 和 result 都是内部的
// Promise 对象的 state 和 result 属性都是内部的。我们无法直接访问它们。但我们可以对它们使用 .then/.catch/.finally 方法。我们在下面对这些方法进行了描述。
// 消费者:then,catch,finally
// Promise 对象充当的是 executor(“生产者代码”或“歌手”)和消费函数(“粉丝”)之间的连接,后者将接收结果或 error。可以通过使用 .then、.catch 和 .finally 方法为消费函数进行注册。
// let promise = new Promise(function (resolve, reject) {
// alert('saaa')
// setTimeout(() => resolve("done"),3000)
// });
// promise.then(
// function (resault){
// alert('xxxx')
// }
// )
// .then 的第一个参数是一个函数,该函数将在 promise resolved 后运行并接收结果。
// .then 的第二个参数也是一个函数,该函数将在 promise rejected 后运行并接收 error。
// 在 reject 的情况下,运行第二个:
// let promise = new Promise(function (resolve, reject) {
// setTimeout((() => reject(new Error('xxxx'))),2000)
// })
// promise.then(
// result = alert(result)
// error = alert(error)
// )
// let promise = new Promise(function (resolve, reject) {
// setTimeout(() => resolve('done'),1000)
// })
// promise.then(alert)
// catch
// 如果我们只对 error 感兴趣,那么我们可以使用 null 作为第一个参数:.then(null, errorHandlingFunction)。或者我们也可以使用 .catch(errorHandlingFunction),其实是一样的:
// let promise = Promise(function (resolve, reject) {
// setTimeout(() => reject(new Error("xxxx")),2000)
// })
// promise.catch(alert)
// 如果我们只对 error 感兴趣,那么我们可以使用 null 作为第一个参数:.then(null, errorHandlingFunction)。或者我们也可以使用 .catch(errorHandlingFunction),其实是一样的:
// catch(f) 调用是 .then(null, f) 的完全的模拟,它只是一个简写形式。
// finally
// new Promise((resolve, reject) => {
// /* 做一些需要时间的事儿,然后调用 resolve/reject */
// })
// // 在 promise 为 settled 时运行,无论成功与否
// .finally(() => stop loading indicator)
// // 所以,加载指示器(loading indicator)始终会在我们处理结果/错误之前停止
// .then(result => show result, err => show error)
// new Promise((resolve, reject) => {
//
// })
// .finally(() => stop)
// .then(result => showResault, error => showError)
// finally 处理程序(handler)没有参数。在 finally 中,我们不知道 promise 是否成功。没关系,因为我们的任务通常是执行“常规”的定稿程序(finalizing procedures)。
// finally 处理程序将结果和 error 传递给下一个处理程序。
// 例如,在这儿结果被从 finally 传递给了 then:
// new Promise((resolve, reject) => {
// setTimeout(() => resolve("result"), 2000)
// })
// .finally(() => alert("Promise ready"))
// .then(result => alert(result)); // <-- .then 对结果进行处理
// new Promise((resolve, reject) => {
// throw new Error("error");
// })
// .finally(() => alert("Promise ready"))
// .catch(err => alert(err)); // <-- .catch 对 error 对象进行处理
// 这非常方便,因为 finally 并不是意味着要处理 promise 的结果。所以它将结果传递了下去。
// 如果 promise 为 pending 状态,.then/catch/finally 处理程序(handler)将等待它。否则,如果 promise 已经是 settled 状态,它们就会运行:
// 下面这 promise 在被创建后立即变为 resolved 状态
// let promise = new Promise(resolve => resolve("done!"));
// promise.then(alert); // done!(现在显示)
// 请注意这使得 promise 比现实生活中的“订阅列表”方案强大得多。如果歌手已经发布了他们的单曲,然后某个人在订阅列表上进行了注册,则他们很可能不会收到该单曲。实际生活中的订阅必须在活动开始之前进行。
// Promise 则更加灵活。我们可以随时添加处理程序(handler):如果结果已经在了,它们就会执行。
// function loadScript(src, callback) {
// let script = document.createElement('script')
// script.src = src
// script.onload = () => callback(null, script)
// script.onerror = () => callback(new Error(`error ${src}`))
// document.head.append(script)
// }
// 改写
function loadScript(scr) {
return new Promise(function (resolve, reject) {
let script =document.createElement('script')
script.src = src
script.onload = () => resolve(script)
script.onerror = () => reject(new Error(`error ${src}`))
document.head.append(script)
})
}
// 用法
let promise =loadScript("xxxxx")
promise.then(
script =>alert(`${script.src} is loaded!`),
error =>alert(`Error: ${error.message}`)
)
// promise.then(script => alert('Another handler...'));
// Promises Callbacks
// Promises 允许我们按照自然顺序进行编码。首先,我们运行 loadScript 和 .then 来处理结果。 在调用 loadScript(script, callback) 时,在我们处理的地方(disposal)必须有一个 callback 函数。换句话说,在调用 loadScript 之前,我们必须知道如何处理结果。
function delay(ms) {
return new Promise(resolve =>setTimeout(resolve, ms));
}
delay(3000).then(() =>alert('runs after 3 seconds'));
// Promise 链
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000); // (*)
}).then(function(result) {// (**)
alert(result); // 1
return result *2;
}).then(function(result) {// (***)
alert(result); // 2
return result *2;
}).then(function(result) {
alert(result); // 4
return result *2;
});
// 它的理念是将 result 通过 .then 处理程序(handler)链进行传递。
// 运行流程如下:
// 初始 promise 在 1 秒后进行 resolve (*),
// 然后 .then 处理程序(handler)被调用 (**)。
// 它返回的值被传入下一个 .then 处理程序(handler)(***)
// ……依此类推。
// 随着 result 在处理程序(handler)链中传递,我们可以看到一系列的 alert 调用:1 → 2 → 4。
// 之所以这么运行,是因为对 promise.then 的调用会返回了一个 promise,所以我们可以在其之上调用下一个 .then。
// 当处理程序(handler)返回一个值时,它将成为该 promise 的 result,所以将使用它调用下一个 .then。
// 新手常犯的一个经典错误:从技术上讲,我们也可以将多个 .then 添加到一个 promise 上。但这并不是 promise 链(chaining)。
// 我们在这里所做的只是一个 promise 的几个处理程序(handler)。它们不会相互传递 result;相反,它们之间彼此独立运行处理任务。
// 这里它的一张示意图(你可以将其与上面的链式调用做一下比较):
// 在同一个 promise 上的所有 .then 获得的结果都相同 — 该 promise 的结果。所以,在上面的代码中,所有 alert 都显示相同的内容:1。
// 实际上我们极少遇到一个 promise 需要多处理程序(handler)的情况。使用链式调用的频率更高。
// let promise = new Promise(function(resolve, reject) {
// setTimeout(() => resolve(1), 1000);
// });
// promise.then(function(result) {
// alert(result); // 1
// return result * 2;
// });
// promise.then(function(result) {
// alert(result); // 1
// return result * 2;
// });
// promise.then(function(result) {
// alert(result); // 1
// return result * 2;
// });
// .then(handler) 中所使用的处理程序(handler)可以创建并返回一个 promise。
// 在这种情况下,其他的处理程序(handler)将等待它 settled 后再获得其结果(result)。
new Promise(function(resolve, reject) {
setTimeout(() => resolve(1), 1000);
}).then(function(result) {
alert(result); // 1
return new Promise((resolve, reject) => {// (*)
setTimeout(() => resolve(result *2), 1000);
});
}).then(function(result) {// (**)
alert(result); // 2
return new Promise((resolve, reject) => {
setTimeout(() => resolve(result *2), 1000);
});
}).then(function(result) {
alert(result); // 4
});
// 这里第一个 .then 显示 1 并在 (*) 行返回 new Promise(…)。1 秒后它会进行 resolve,然后 result(resolve 的参数,在这里它是 result*2)被传递给第二个 .then 的处理程序(handler)。这个处理程序(handler)位于 (**) 行,它显示 2,并执行相同的动作(action)。
Promise.all()// 所有结果成功
Promise.race()//只要有一个返回不管成功或者失败