标签:roc 没有 开始 递归 添加 分类 方式 异常 术语
一个函数执行之后,在它后面顺序编写的代码中,如果能够直接使用它的返回结果或者它修改之后的引用参数,那么我们通常认为该函数是同步的。
如果一个函数的执行结果或者其修改的引用参数,需要通过设置回调函数或者回调事件的方式来获取,而在其后顺序编写的代码中无法直接获取的话,那么我们通常认为这样的函数是异步的。
阻塞带来的问题是当前线程(或进程)会陷入等待,一直等到阻塞结束,这样就会造成线程(或进程)资源的浪费。所以通常认为阻塞是不够高效的。
如果要编写非阻塞代码,使用同步方式会变得有些复杂,且不够灵活。同步方式的非阻塞代码通常会使用 select 模式,例如 curl_multi_select、stream_select、socket_select等就是PHP中提供的一些典型的 select 模式的函数。我们说它复杂且不够灵活,是因为例如使用上面的 select 模式编写同步的非阻塞代码时我们需要先构造一个并发任务的列表,之后手动构造循环来执行这些并发的任务,在循环开始之后,虽然这几个任务可以并发,但是这个循环相对于其后的代码总体上仍然是阻塞的,我们要想拿到这些并发任务的结果时,仍然需要等待。select 虽然可以同时等待多个任务中某一个或几个就位后,再执行后续操作,但仍然有一部分时间是被等待消耗掉的。而且如果是纯同步非阻塞的情况下,我们也很难在循环开始后,动态添加更多的任务到这个循环中去。所以希望程序能够更加高效、更加灵活,就需要引入异步方式。
回调是最简单直接的异步模式,只要在调用异步函数时设置一个或多个回调函数,函数就会在完成时自动调用回调函数。如果你的程序逻辑够简单,简单的一两层回调也许并不会让你觉得异步方式的编程有什么麻烦。但如果你的程序逻辑一旦有些复杂,你可能就会被层层回调搞得疲惫不堪了。当然,实际上你的程序需要层层回调的原因,也许并不是你的程序逻辑真的复杂,而是你没有办法将回调函数中的参数结果传出来,所以你就不得不将另一个回调函数传进去。
Promise要解决的问题是,如何将回调方法的参数从回调方法中传递出来,让它可以像同步函数的返回结果一样,在回调函数以外的控制范围内,可以传递和复用。
Promise是抽象异步处理对象以及对其进行各种操作的组件
Promise 表示一个异步操作的最终结果,与之进行交互的方式主要是 then 方法,该方法注册了两个回调函数,用于接收 Promise 的终值或本 Promise 不能执行的原因。
一个 Promise 的当前状态必须为以下三种状态中的一种:等待态(Pending)、执行态(Fulfilled)和拒绝态(Rejected)。
等待态(Pending)
处于等待态时,promise 需要满足以下条件:
执行态(Fulfilled)
处于执行态时,promise 需要满足以下条件:
拒绝态(Rejected)
处于拒绝态时,promise 需满足以下条件:
这里的不可变指的是恒等(即可用 === 判断相等),而不是意味着更深层次的不可变(指当 value 或 reason 不是基本值时,只要求其引用地址相等,但属性值可被更改)
一个 promise 必须提供一个 then 方法以访问其当前值、终值和拒因。
promise 的 then 方法接受两个参数:
promise.then(onFulfilled, onRejected)
参数可选
onFulfilled 和 onRejected 都是可选参数。
onFulfilled 特性
如果 onFulfilled 是函数:
onRejected 特性
如果onRejected 是函数:
onFulfilled 和 onRejected 只有在执行环境堆栈仅包含平台代码时才可被调用(平台代码:指的是引擎、环境以及 promise 的实施代码。实践中要确保 onFulfilled 和 onRejected 方法异步执行,且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。这个事件队列可以采用"宏任务macrotask"机制或"微任务microtask"机制来实现。由于 promise 的实施代码本身就是平台代码(即都是JavaScript),故代码自身在处理在处理程序时可能已经包含一个任务调度队列。)
macrotask 和 microtask 两个概念,这表示异步任务的两种分类。在挂起任务时,JS 引擎会将所有任务按照类别分到这两个队列中,首先在 macrotask 的队列(这个队列也被叫做 task queue)中取出第一个任务,执行完毕后取出 microtask 队列中的所有任务顺序执行;之后再取 macrotask 任务,周而复始,直至两个队列的任务都取完。
两个类别的具体分类如下:
onFulfilled 和 onRejected 必须被作为函数调用(即没有 this 值)
then 方法可以被同一个 promise 调用多次
then 方法必须返回一个 promise 对象
promise2 = promise1.then(onFulfilled, onRejected);
不论 promise1 被 reject 还是被 resolve 时 promise2 都会被 resolve,只有出现异常时才会被 rejected。
Promise 解决过程是一个抽象的操作,其需输入一个 promise 和一个值,我们表示为 [ [ Resolve ] ] (promise,x),如果 x 有 then 方法且看上去像一个 Promise ,解决程序即尝试使 promise 接受 x 的状态;否则其用 x 的值来执行 promise。
这种 thenable 的特性使得 Promise 的实现更具有通用性:只要其暴露出一个遵循 Promise/A+协议的 then 方法即可;这同时也使遵循 Promise/A+ 规范的实现可以与那些不太规范但可用的实现能良好共存。
运行 [ [ Resolve ] ] (promise,x) 需要遵循以下步骤:
x 与 promise 相等
如果 promise 和 x 指向同一个对象,以 TypeError 为拒因拒绝执行 promise
x 为 promise
如果 x 为 Promise,则使 promise 接受 x 的状态:
x 为对象或函数
如果 x 为对象或函数:
如果一个 promise 被一个循环的 thenable 链中的对象解决,而 [ [Resolve] ](promise,thenable) 的递归性质又使得其被再次调用,根据上述的算法将会陷入无限递归之中。算法虽不强制要求,但也鼓励施者检测这样的递归是否存在,若检测到存在则以一个可识别的 TypeError 为拒因来拒绝 promise。
标签:roc 没有 开始 递归 添加 分类 方式 异常 术语
原文地址:https://www.cnblogs.com/xi-jie/p/11972254.html