用于实现JS的异步机制, 非常重要!!!
执行流程(无其他异步操作, 如定时器):
#mermaid-svg-lcs5ne0lcHB1xE2P .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .label text{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .node rect,#mermaid-svg-lcs5ne0lcHB1xE2P .node circle,#mermaid-svg-lcs5ne0lcHB1xE2P .node ellipse,#mermaid-svg-lcs5ne0lcHB1xE2P .node polygon,#mermaid-svg-lcs5ne0lcHB1xE2P .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-lcs5ne0lcHB1xE2P .node .label{text-align:center;fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .node.clickable{cursor:pointer}#mermaid-svg-lcs5ne0lcHB1xE2P .arrowheadPath{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-lcs5ne0lcHB1xE2P .flowchart-link{stroke:#333;fill:none}#mermaid-svg-lcs5ne0lcHB1xE2P .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-lcs5ne0lcHB1xE2P .edgeLabel rect{opacity:0.9}#mermaid-svg-lcs5ne0lcHB1xE2P .edgeLabel span{color:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-lcs5ne0lcHB1xE2P .cluster text{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-lcs5ne0lcHB1xE2P .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-lcs5ne0lcHB1xE2P text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-lcs5ne0lcHB1xE2P .actor-line{stroke:grey}#mermaid-svg-lcs5ne0lcHB1xE2P .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-lcs5ne0lcHB1xE2P #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .sequenceNumber{fill:#fff}#mermaid-svg-lcs5ne0lcHB1xE2P #sequencenumber{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P #crosshead path{fill:#333;stroke:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .messageText{fill:#333;stroke:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-lcs5ne0lcHB1xE2P .labelText,#mermaid-svg-lcs5ne0lcHB1xE2P .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-lcs5ne0lcHB1xE2P .loopText,#mermaid-svg-lcs5ne0lcHB1xE2P .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-lcs5ne0lcHB1xE2P .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-lcs5ne0lcHB1xE2P .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-lcs5ne0lcHB1xE2P .noteText,#mermaid-svg-lcs5ne0lcHB1xE2P .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-lcs5ne0lcHB1xE2P .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-lcs5ne0lcHB1xE2P .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-lcs5ne0lcHB1xE2P .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-lcs5ne0lcHB1xE2P .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .section{stroke:none;opacity:0.2}#mermaid-svg-lcs5ne0lcHB1xE2P .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-lcs5ne0lcHB1xE2P .section2{fill:#fff400}#mermaid-svg-lcs5ne0lcHB1xE2P .section1,#mermaid-svg-lcs5ne0lcHB1xE2P .section3{fill:#fff;opacity:0.2}#mermaid-svg-lcs5ne0lcHB1xE2P .sectionTitle0{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .sectionTitle1{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .sectionTitle2{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .sectionTitle3{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-lcs5ne0lcHB1xE2P .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .grid path{stroke-width:0}#mermaid-svg-lcs5ne0lcHB1xE2P .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-lcs5ne0lcHB1xE2P .task{stroke-width:2}#mermaid-svg-lcs5ne0lcHB1xE2P .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .taskText:not([font-size]){font-size:11px}#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-lcs5ne0lcHB1xE2P .task.clickable{cursor:pointer}#mermaid-svg-lcs5ne0lcHB1xE2P .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-lcs5ne0lcHB1xE2P .taskText0,#mermaid-svg-lcs5ne0lcHB1xE2P .taskText1,#mermaid-svg-lcs5ne0lcHB1xE2P .taskText2,#mermaid-svg-lcs5ne0lcHB1xE2P .taskText3{fill:#fff}#mermaid-svg-lcs5ne0lcHB1xE2P .task0,#mermaid-svg-lcs5ne0lcHB1xE2P .task1,#mermaid-svg-lcs5ne0lcHB1xE2P .task2,#mermaid-svg-lcs5ne0lcHB1xE2P .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutside0,#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutside2{fill:#000}#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutside1,#mermaid-svg-lcs5ne0lcHB1xE2P .taskTextOutside3{fill:#000}#mermaid-svg-lcs5ne0lcHB1xE2P .active0,#mermaid-svg-lcs5ne0lcHB1xE2P .active1,#mermaid-svg-lcs5ne0lcHB1xE2P .active2,#mermaid-svg-lcs5ne0lcHB1xE2P .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-lcs5ne0lcHB1xE2P .activeText0,#mermaid-svg-lcs5ne0lcHB1xE2P .activeText1,#mermaid-svg-lcs5ne0lcHB1xE2P .activeText2,#mermaid-svg-lcs5ne0lcHB1xE2P .activeText3{fill:#000 !important}#mermaid-svg-lcs5ne0lcHB1xE2P .done0,#mermaid-svg-lcs5ne0lcHB1xE2P .done1,#mermaid-svg-lcs5ne0lcHB1xE2P .done2,#mermaid-svg-lcs5ne0lcHB1xE2P .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-lcs5ne0lcHB1xE2P .doneText0,#mermaid-svg-lcs5ne0lcHB1xE2P .doneText1,#mermaid-svg-lcs5ne0lcHB1xE2P .doneText2,#mermaid-svg-lcs5ne0lcHB1xE2P .doneText3{fill:#000 !important}#mermaid-svg-lcs5ne0lcHB1xE2P .crit0,#mermaid-svg-lcs5ne0lcHB1xE2P .crit1,#mermaid-svg-lcs5ne0lcHB1xE2P .crit2,#mermaid-svg-lcs5ne0lcHB1xE2P .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-lcs5ne0lcHB1xE2P .activeCrit0,#mermaid-svg-lcs5ne0lcHB1xE2P .activeCrit1,#mermaid-svg-lcs5ne0lcHB1xE2P .activeCrit2,#mermaid-svg-lcs5ne0lcHB1xE2P .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-lcs5ne0lcHB1xE2P .doneCrit0,#mermaid-svg-lcs5ne0lcHB1xE2P .doneCrit1,#mermaid-svg-lcs5ne0lcHB1xE2P .doneCrit2,#mermaid-svg-lcs5ne0lcHB1xE2P .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-lcs5ne0lcHB1xE2P .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-lcs5ne0lcHB1xE2P .milestoneText{font-style:italic}#mermaid-svg-lcs5ne0lcHB1xE2P .doneCritText0,#mermaid-svg-lcs5ne0lcHB1xE2P .doneCritText1,#mermaid-svg-lcs5ne0lcHB1xE2P .doneCritText2,#mermaid-svg-lcs5ne0lcHB1xE2P .doneCritText3{fill:#000 !important}#mermaid-svg-lcs5ne0lcHB1xE2P .activeCritText0,#mermaid-svg-lcs5ne0lcHB1xE2P .activeCritText1,#mermaid-svg-lcs5ne0lcHB1xE2P .activeCritText2,#mermaid-svg-lcs5ne0lcHB1xE2P .activeCritText3{fill:#000 !important}#mermaid-svg-lcs5ne0lcHB1xE2P .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-lcs5ne0lcHB1xE2P g.classGroup text .title{font-weight:bolder}#mermaid-svg-lcs5ne0lcHB1xE2P g.clickable{cursor:pointer}#mermaid-svg-lcs5ne0lcHB1xE2P g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-lcs5ne0lcHB1xE2P g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-lcs5ne0lcHB1xE2P .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-lcs5ne0lcHB1xE2P .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-lcs5ne0lcHB1xE2P .dashed-line{stroke-dasharray:3}#mermaid-svg-lcs5ne0lcHB1xE2P #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P .commit-id,#mermaid-svg-lcs5ne0lcHB1xE2P .commit-msg,#mermaid-svg-lcs5ne0lcHB1xE2P .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-lcs5ne0lcHB1xE2P g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-lcs5ne0lcHB1xE2P g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-lcs5ne0lcHB1xE2P g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-lcs5ne0lcHB1xE2P .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-lcs5ne0lcHB1xE2P .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-lcs5ne0lcHB1xE2P .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-lcs5ne0lcHB1xE2P .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-lcs5ne0lcHB1xE2P .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-lcs5ne0lcHB1xE2P .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-lcs5ne0lcHB1xE2P .edgeLabel text{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-lcs5ne0lcHB1xE2P .node circle.state-start{fill:black;stroke:black}#mermaid-svg-lcs5ne0lcHB1xE2P .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-lcs5ne0lcHB1xE2P #statediagram-barbEnd{fill:#9370db}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-state .divider{stroke:#9370db}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-lcs5ne0lcHB1xE2P .note-edge{stroke-dasharray:5}#mermaid-svg-lcs5ne0lcHB1xE2P .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-lcs5ne0lcHB1xE2P .error-icon{fill:#522}#mermaid-svg-lcs5ne0lcHB1xE2P .error-text{fill:#522;stroke:#522}#mermaid-svg-lcs5ne0lcHB1xE2P .edge-thickness-normal{stroke-width:2px}#mermaid-svg-lcs5ne0lcHB1xE2P .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-lcs5ne0lcHB1xE2P .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-lcs5ne0lcHB1xE2P .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-lcs5ne0lcHB1xE2P .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-lcs5ne0lcHB1xE2P .marker{fill:#333}#mermaid-svg-lcs5ne0lcHB1xE2P .marker.cross{stroke:#333} :root { --mermaid-font-family: "trebuchet ms", verdana, arial;} #mermaid-svg-lcs5ne0lcHB1xE2P { color: rgba(0, 0, 0, 0.75); font: ; } new Promise 执行传入的函数 遇到resolve promise的状态由pending改为fulfilled 遇到reject promise的状态由pending改为rejected 继续执行函数之后的语句,如再遇到reject/resolve则忽视 返回一个promise对象 调用then/catch 调用then/catch传入的函数,对应参数为上面resolve/reject函数传入的参数用一段代码理解一下:
var p = new Promise(function(resolve, reject){ console.log(1) resolve(2) resolve(3) reject(4) console.log(5) }) console.log(6) p.then(function(val){ console.log('then',val) }).catch(function(val){ console.log('catch', val) }) console.log(7) 创建一个Promise对象的时候, 立即执行传入的function.输出1; 遇到resolve, pending状态改为fulfilled(已完成). 并保留参数2(后面then要用)之后遇到resolve和reject, 由于状态已经不是pending了, 直接忽略这两个函数.打印5. 整个函数执行完成, 返回一个Promise对象(的引用)给变量p.打印6. 遇到then/catch, 现在的状态是fulfilled, 所以执行then.(如果Promise状态为rejected, 执行catch的回调函数). 但不是立即执行, 而是把传入的function加到事件队列尾部(你需要先了解JS的事件队列).打印7. 主程序运行完毕, 然后是下一个事件, 就是then里面的这个函数执行. 函数接受一个参数, 就是上面resolve传入的参数2. 所以这里打印then 2.顺序输出为: 1, 5, 6, 7, then 2除了 then(onresolve).catch(onreject) 的写法, 也可以不写catch, 把两个函数都作为then的参数, 即 then(onresolve, onreject) 的写法, 不过前者更直观一些, 推荐.
带有定时器的Promise
前面的是一个非常简单的例子. 如果我们在Promise传入的函数中设置了一个定时器, 延迟一定时间后在改变Promise的状态, 这样的话下面的then/catch都只能读取到pending状态? 这样会发生什么情况呢? 如下代码:
var p = new Promise(function(resolve, reject){ console.log(1) //把修改状态的语句写入定时器. setTimeout(function(){ resolve(2) },3000) console.log(5) }) console.log(6) p.then(function(val){ console.log('then',val) }).catch(function(val){ console.log('catch', val) }) console.log(7)直接说结论, 输出的结果同上. 不过最后一个结果会等待三秒才输出.
当我们调用then/catch的时候, 如果当前的状态为pending, 则将对应的函数压入一个队列, 当改变Promise状态时, 再逐个执行这些函数.
下面来两段一个大佬自己实现的模拟Promise源码, 很觉得很有助于理解Promise的实现原理和运行机制.
原博客链接: https://www.jianshu.com/p/43de678e918a
思想还是很简单的:
当我们在创建Promise传入的回调函数中, 如果遇到resolve/reject, 判断当前状态是否为pending, 不是pending则直接忽略.
如果是pending, 则修改当前状态为fulfilled/rejected.
看第二段代码, 当我们执行then函数的时候, 如果Promise的状态为pending, 把对应的执行函数压到队列里面. 如果为fulfilled/rejected, 则直接执行then参数里面的函数.
再回到第一段代码, 就是上面then执行时遇到pending的情况, 当pending转化为fulfilled/rejected的时候, 调用相应方法, 查询执行函数队列, 并按顺序执行队列里面的函数. 这样就比较完美的实现了异步机制.
对于下面的第二段代码, 有个地方没实现好, then方法应该是异步执行的, 这里当Promise已经是fulfilled时, 直接执行then传入的回调函数. 我觉得应该这样去实现: setTimeout(()=>{onFulfilled(_value)},0).
// 添加resovle时执行的函数 _resolve (val) { if (this._status !== PENDING) return // 依次执行成功队列中的函数,并清空队列 const run = () => { this._status = FULFILLED this._value = val let cb; while (cb = this._fulfilledQueues.shift()) { cb(val) } } // 为了支持同步的Promise,这里采用异步调用 setTimeout(() => run(), 0) } // 添加reject时执行的函数 _reject (err) { if (this._status !== PENDING) return // 依次执行失败队列中的函数,并清空队列 const run = () => { this._status = REJECTED this._value = err let cb; while (cb = this._rejectedQueues.shift()) { cb(err) } } // 为了支持同步的Promise,这里采用异步调用 setTimeout(run, 0) }then的实现:
// 添加then方法 then (onFulfilled, onRejected) { const { _value, _status } = this switch (_status) { // 当状态为pending时,将then方法回调函数加入执行队列等待执行 case PENDING: this._fulfilledQueues.push(onFulfilled) this._rejectedQueues.push(onRejected) break // 当状态已经改变时,立即执行对应的回调函数 case FULFILLED: onFulfilled(_value) break case REJECTED: onRejected(_value) break } // 返回一个新的Promise对象 return new MyPromise((onFulfilledNext, onRejectedNext) => { }) }但是then地用法不止如此, 有时候你可能会看到一连串的then. 在上面代码也看到, then返回的是另一个Promise对象, 所以then之后可以继续接then的.返回的Promise对象的状态和参数是怎么样的呢? 源码我就不继续举了, 来个例子了解一下就好了.
var p = new Promise(function(resolve, reject){ resolve(666) }) .then(function(val){ console.log('then',val) return 'hello' }).then(function(val){ console.log(val) return 'world' }).then(function(val){ console.log(val) return new Promise(function(resolve, reject){ setTimeout(function(){ reject('goodbye') },3000) }) }).catch(function(val){ console.log(val) return 'see you again' }).then(function(val){ console.log(val) }) console.log(999)代码略长, 但是不难理解.
创建一个Promise对象, 调用第一个then方法, 这个是和上面讲的列子是一样的. 不同的是, 第一个then返回一个hello字符串.调用第二个then, 我们可以看到它的回调函数传入的参数就是上一个then返回的内容. 说明调用then方法的时候Promise内部会帮我们创建一个新的Promise对象, 而且是调用了resolve并传入then返回的值(hello).然后到第三个then了, 也是输出上一个then的返回值. 但是这个then返回的是一个Promise对象. 直接返回Promise对象的话这个就直接把这个promise对象最为then的返回值, 相当于之后的then/catch都是这个Promise对象的调用.因为上一个then返回的是一个rejected状态的Promise对象, 所以找catch来调用. 在catch里面也是直接返回一个字符串.下一个调用到的是then而不是catch, 说明即使在catch里面返回的非promise数据, 系统默认新建的还是fulfilled状态的Promise对象(就是上面说的默认执行了resolve).这一连串的then并不会阻塞主函数的运行, 所以输出的结果为: 999, then 666, hello, world, goodbye, see you again.
定义函数时可以在函数前添加asnyc关键字, 函数执行与普通函数一致, 只不过对返回值进行了Promise的封装. 返回的Promise状态为fullfilled. (类似下面的封装).
function bar(fn, self){ return function(...rest){ let result = fn.apply(self, rest) return Promise.resolve(result) } }async的做法非常好理解. 但是await做的事情就多一些了. 首先, await必须在async的函数内部使用. await可以看作是一个运算符, 右边必须是一个Promise对象, 由于async返回的一定是一个promise对象, 所以await后面常跟async的函数(有点套娃的感觉, 但是只要理解上面说的await的用法, 这个说法就很容易接受). await会阻塞当前函数的执行, 直到await拿到结果, 才会继续执行后面的内容. 那await等的是什么呢? 等的是对应的Promise对象, 等到他状态变为resolved.
console.log(1) async function foo(){ console.log(2) let tmp = await new Promise(resolve=>{ setTimeout(function(){ resolve(3) },2000) }) console.log(tmp,4) console.log(5) return 6 } console.log(foo()) console.log(7) //输出结果为: 1 2 Promise<pending> 7 (3,4) 5从结果可以看出, await部分之前与普通函数一样正常执行. 但是之后的部分直接作为一个Promise对象封装并返回. 另外, await运算后不是一个Promise对象, 而是resolve的传入. 上面的函数和这个这个写法是等价的.
async function foo(){ return new Promise(resolve=>{ setTimeout(()=>{ resolve(3) },2000) }).then(v=>{ console.log(v,4) console.log(5) return 6 }) }