@@ -156,8 +156,7 @@ Local<FunctionTemplate> Blob::GetConstructorTemplate(Environment* env) {
156156 Isolate* isolate = env->isolate ();
157157 tmpl = NewFunctionTemplate (isolate, nullptr );
158158 tmpl->InstanceTemplate ()->SetInternalFieldCount (Blob::kInternalFieldCount );
159- tmpl->SetClassName (
160- FIXED_ONE_BYTE_STRING (env->isolate (), " Blob" ));
159+ tmpl->SetClassName (FIXED_ONE_BYTE_STRING (env->isolate (), " Blob" ));
161160 SetProtoMethod (isolate, tmpl, " getReader" , GetReader);
162161 SetProtoMethod (isolate, tmpl, " slice" , ToSlice);
163162 env->set_blob_constructor_template (tmpl);
@@ -255,8 +254,7 @@ void Blob::New(const FunctionCallbackInfo<Value>& args) {
255254 }
256255
257256 auto blob = Create (env, DataQueue::CreateIdempotent (std::move (entries)));
258- if (blob)
259- args.GetReturnValue ().Set (blob->object ());
257+ if (blob) args.GetReturnValue ().Set (blob->object ());
260258}
261259
262260void Blob::GetReader (const FunctionCallbackInfo<Value>& args) {
@@ -278,8 +276,7 @@ void Blob::ToSlice(const FunctionCallbackInfo<Value>& args) {
278276 size_t start = args[0 ].As <Uint32>()->Value ();
279277 size_t end = args[1 ].As <Uint32>()->Value ();
280278 BaseObjectPtr<Blob> slice = blob->Slice (env, start, end);
281- if (slice)
282- args.GetReturnValue ().Set (slice->object ());
279+ if (slice) args.GetReturnValue ().Set (slice->object ());
283280}
284281
285282void Blob::MemoryInfo (MemoryTracker* tracker) const {
@@ -343,6 +340,7 @@ void Blob::Reader::Pull(const FunctionCallbackInfo<Value>& args) {
343340 Environment* env = Environment::GetCurrent (args);
344341 Blob::Reader* reader;
345342 ASSIGN_OR_RETURN_UNWRAP (&reader, args.This ());
343+ reader->pull_pending_ = false ;
346344
347345 CHECK (args[0 ]->IsFunction ());
348346 Local<Function> fn = args[0 ].As <Function>();
@@ -414,19 +412,31 @@ void Blob::Reader::Pull(const FunctionCallbackInfo<Value>& args) {
414412void Blob::Reader::SetWakeup (const FunctionCallbackInfo<Value>& args) {
415413 Blob::Reader* reader;
416414 ASSIGN_OR_RETURN_UNWRAP (&reader, args.This ());
415+ if (args[0 ]->IsUndefined ()) {
416+ reader->wakeup_ .Reset ();
417+ return ;
418+ }
417419 CHECK (args[0 ]->IsFunction ());
418420 reader->wakeup_ .Reset (args.GetIsolate (), args[0 ].As <Function>());
419421}
420422
421- void Blob::Reader::NotifyPull () {
423+ void Blob::Reader::NotifyPull (bool fin ) {
422424 if (wakeup_.IsEmpty () || !env ()->can_call_into_js ()) return ;
425+ // FIN notifications always fire — they must not be suppressed by
426+ // pull_pending_ because there will be no further notifications to
427+ // wake the iterator. Regular data notifications respect pull_pending_
428+ // to coalesce multiple deliveries within a single packet.
429+ if (!fin && pull_pending_) return ;
430+ pull_pending_ = true ;
423431 HandleScope handle_scope (env ()->isolate ());
424432 Local<Function> fn = wakeup_.Get (env ()->isolate ());
425- MakeCallback (fn, 0 , nullptr );
433+ // Pass fin as the first argument so the JS iterator knows EOS is
434+ // imminent and should pull again without waiting for another wakeup.
435+ Local<Value> argv[] = {v8::Boolean::New (env ()->isolate (), fin)};
436+ MakeCallback (fn, 1 , argv);
426437}
427438
428- BaseObjectPtr<BaseObject>
429- Blob::BlobTransferData::Deserialize (
439+ BaseObjectPtr<BaseObject> Blob::BlobTransferData::Deserialize (
430440 Environment* env,
431441 Local<Context> context,
432442 std::unique_ptr<worker::TransferData> self) {
@@ -448,10 +458,10 @@ std::unique_ptr<worker::TransferData> Blob::CloneForMessaging() const {
448458void Blob::StoreDataObject (const FunctionCallbackInfo<Value>& args) {
449459 Realm* realm = Realm::GetCurrent (args);
450460
451- CHECK (args[0 ]->IsString ()); // ID key
461+ CHECK (args[0 ]->IsString ()); // ID key
452462 CHECK (Blob::HasInstance (realm->env (), args[1 ])); // Blob
453- CHECK (args[2 ]->IsUint32 ()); // Length
454- CHECK (args[3 ]->IsString ()); // Type
463+ CHECK (args[2 ]->IsUint32 ()); // Length
464+ CHECK (args[3 ]->IsString ()); // Type
455465
456466 BlobBindingData* binding_data = realm->GetBindingData <BlobBindingData>();
457467 Isolate* isolate = realm->isolate ();
@@ -531,12 +541,8 @@ void BlobBindingData::StoredDataObject::MemoryInfo(
531541}
532542
533543BlobBindingData::StoredDataObject::StoredDataObject (
534- const BaseObjectPtr<Blob>& blob_,
535- size_t length_,
536- const std::string& type_)
537- : blob(blob_),
538- length(length_),
539- type(type_) {}
544+ const BaseObjectPtr<Blob>& blob_, size_t length_, const std::string& type_)
545+ : blob(blob_), length(length_), type(type_) {}
540546
541547BlobBindingData::BlobBindingData (Realm* realm, Local<Object> wrap)
542548 : SnapshotableObject(realm, wrap, type_int) {
@@ -550,8 +556,7 @@ void BlobBindingData::MemoryInfo(MemoryTracker* tracker) const {
550556}
551557
552558void BlobBindingData::store_data_object (
553- const std::string& uuid,
554- const BlobBindingData::StoredDataObject& object) {
559+ const std::string& uuid, const BlobBindingData::StoredDataObject& object) {
555560 data_objects_[uuid] = object;
556561}
557562
@@ -566,8 +571,7 @@ void BlobBindingData::revoke_data_object(const std::string& uuid) {
566571BlobBindingData::StoredDataObject BlobBindingData::get_data_object (
567572 const std::string& uuid) {
568573 auto entry = data_objects_.find (uuid);
569- if (entry == data_objects_.end ())
570- return BlobBindingData::StoredDataObject {};
574+ if (entry == data_objects_.end ()) return BlobBindingData::StoredDataObject{};
571575 return entry->second ;
572576}
573577
0 commit comments