相比V1版本这边做了以下修改:
1) 函数命名尽量与js版保持一致,js中的then在这边叫Next(因为then是lua的关键字)
2) m_DoNextObj这边变成了一个列表,这样改动的结果就是:之前对象间会组成单向链表;这边是一个单向的树。
3) m_DoNextObj.run函数这边改成了m_OnFulfilled和m_OnRejected函数(为了与js保持一致)
4) SetFinished函数改成了FulFulled和Reject函数
5) V1版本,Promise对象会作为参数传入run函数,需要手动调用SetFinished;这边全部封装在Promise内部自动完成;
Promise.lua
---@class Promise local Promise = {} Promise.__cname = "Promise" Promise.__index = Promise local State = { Pending = 0, FulFilled = 1, Rejected = -1, } ------------------ 内部函数 ------------------ ---@type Promise local Inner = {} local function OnFulFilled_Default(x) return x end local function OnRejected_Default(x) error(x) end local function IsCallbackResultPromise(result) if "table" == type(result) then local result = result.isPromise or "Promise" == result.__cname return result end return false end ---@param prmNode Promise ---@param otherPrm Promise function Inner.WaitOtherPromise(prmNode, otherPrm) if otherPrm:IsPending() then --[[ --这样会多创建一个临时Promise对象, 所以这边用下面的方式 local tempPrm = otherPrm:Next(function(value) prmNode:FulFilled(value) end, function(reason) prmNode:Reject(reason) end) ]] --otherPrm作为子树的新Root prmNode.m_TransitStateFlag = true table.insert(otherPrm.m_NextList, prmNode) else Inner.TransitionState(prmNode, otherPrm.m_State, otherPrm.m_Value) end end function Inner:NextRun() local nextList = self.m_NextList local isFulFilled = (self.m_State == State.FulFilled) for i, v in ipairs(nextList) do local nextNode = nextList[i] if true == nextNode.m_TransitStateFlag then --callback被调用过了 Inner.TransitionState(nextNode, self.m_State, self.m_Value) else local isSucc, result, promiseFlag if isFulFilled then isSucc, result, promiseFlag = pcall(nextNode.m_OnFulFilled, self.m_Value) else isSucc, result, promiseFlag = pcall(nextNode.m_OnRejected, self.m_Value) end if isSucc then if promiseFlag or IsCallbackResultPromise(result) then Inner.WaitOtherPromise(nextNode, result) else nextNode:FulFilled(result) end else print(debug.traceback(result, 1)) end end end for i=#nextList,1,-1 do nextList[i] = nil end end function Inner:TransitionState(state, value) if self.m_State == state or self.m_State ~= State.Pending then return end self.m_State = state self.m_Value = value Inner.NextRun(self) end ------------------ function Promise.new() local inst = {} setmetatable(inst, Promise) inst:ctor() return inst end function Promise:ctor() self.m_State = State.Pending self.m_Value = nil ---@type Promise[] self.m_NextList = {} self.m_OnFulFilled = OnFulFilled_Default self.m_OnRejected = OnRejected_Default self.m_TransitStateFlag = nil end ---@param onFulFilled fun(value):any ---@param onRejected fun(reason):any ---@return Promise function Promise:Next(onFulFilled, onRejected) local prmNode = Promise.new() prmNode.m_OnFulFilled = onFulFilled or OnFulFilled_Default prmNode.m_OnRejected = onRejected or OnRejected_Default table.insert(self.m_NextList, prmNode) if self.m_State ~= State.Pending then Inner.NextRun(self) end return prmNode end function Promise:FulFilled(result) if self.m_State == State.Pending then self.m_State = State.FulFilled self.m_Value = result Inner.NextRun(self) end end function Promise:Reject(reason) if self.m_State == State.Pending then self.m_State = State.Rejected self.m_Value = reason Inner.NextRun(self) end end ---@return boolean, boolean isPending, isFulFilled function Promise:GetState() local isPending = self.m_State == State.Pending local isFulFilled = self.m_State == State.FulFilled return isPending, isFulFilled end ---@return boolean function Promise:IsPending() return self.m_State == State.Pending end function Promise:GetValue() return self.m_Value end return Promise
一些使用例子
例1) 先加载A,再加载B,再加载C
local textList = {} local resAPrm = LoadResAsync("ResA") local prm1 = resAPrm:Next(function(textA) print("ResA load finish") table.insert(textList, textA) --a加载完, 加载b local resBPrm = LoadResAsync("ResB") return resBPrm end) local prm2 = prm1:Next(function(textB) --prm2收到的是resBPrm的值 print("ResB load finish") table.insert(textList, textB) --b加载完, 加载c local resCPrm = LoadResAsync("ResC") return resCPrm end) local lastPrm = prm2:Next(function(textC) --lastPrm收到的是resCPrm的值 table.insert(textList, textC) print(unpack(textList)) end)
执行链分析:
例2) A加载完同时加载B, C, D;B, C, D全部加载完,才加载E
关于LoadResAsync
---@type MsgLoop local MsgLoop = require("MsgLoop") local _MsgLoop = MsgLoop.new(60) local function LoadResAsync(res) local connector = Promise.new() --假装加载资源 _MsgLoop:PostRun(function(data) connector:FulFilled(data) end, 2, res) return connector end --逻辑代码写在StartLoop前 require("test.lua") _MsgLoop:StartLoop()
MsgLoop参考这边:消息循环
标签:function,end,self,lua,State,promise,Promise,结束,local From: https://www.cnblogs.com/sailJs/p/18351851