| 172 | } |
| 173 | |
| 174 | doWrite(req, bufs) { |
| 175 | assert(this[kCurrentWriteRequest] === null); |
| 176 | assert(this[kCurrentShutdownRequest] === null); |
| 177 | |
| 178 | if (this[kPendingClose]) { |
| 179 | // If doClose is pending, the stream & this._handle are gone. We can't do |
| 180 | // anything. doClose will call finishWrite with ECANCELED for us shortly. |
| 181 | this[kCurrentWriteRequest] = req; // Store req, for doClose to cancel |
| 182 | return 0; |
| 183 | } else if (this._handle === null) { |
| 184 | // If this._handle is already null, there is nothing left to do with a |
| 185 | // pending write request, so we discard it. |
| 186 | return 0; |
| 187 | } |
| 188 | |
| 189 | const handle = this._handle; |
| 190 | |
| 191 | const self = this; |
| 192 | |
| 193 | let pending = bufs.length; |
| 194 | |
| 195 | this.stream.cork(); |
| 196 | // Use `var` over `let` for performance optimization. |
| 197 | // eslint-disable-next-line no-var |
| 198 | for (var i = 0; i < bufs.length; ++i) |
| 199 | this.stream.write(bufs[i], done); |
| 200 | this.stream.uncork(); |
| 201 | |
| 202 | // Only set the request here, because the `write()` calls could throw. |
| 203 | this[kCurrentWriteRequest] = req; |
| 204 | |
| 205 | function done(err) { |
| 206 | if (!err && --pending !== 0) |
| 207 | return; |
| 208 | |
| 209 | // Ensure that this is called once in case of error |
| 210 | pending = 0; |
| 211 | |
| 212 | let errCode = 0; |
| 213 | if (err) { |
| 214 | errCode = uv[`UV_${err.code}`] || uv.UV_EPIPE; |
| 215 | } |
| 216 | |
| 217 | // Ensure that write was dispatched |
| 218 | setImmediate(() => { |
| 219 | self.finishWrite(handle, errCode); |
| 220 | }); |
| 221 | } |
| 222 | |
| 223 | return 0; |
| 224 | } |
| 225 | |
| 226 | // handle === this._handle except when called from doClose(). |
| 227 | finishWrite(handle, errCode) { |